汇编语言的过程调用与c语言的函数调用
- 格式:docx
- 大小:16.02 KB
- 文档页数:4
c语言调用汇编语言函数的方式以C语言调用汇编语言函数的方式在编程中,有时需要使用汇编语言来实现一些特定的功能。
但是,由于汇编语言复杂且难以维护,因此我们通常使用高级语言如C语言来编写主要的程序代码。
在这种情况下,我们需要一种方法来调用汇编语言函数,以便在程序中使用它们。
本文将介绍如何使用C 语言调用汇编语言函数。
1. 定义汇编函数我们需要编写一个汇编函数来执行我们需要的操作。
汇编函数可以使用任何汇编语言,但是必须遵循特定的调用约定。
在x86架构中,调用约定指定了函数参数的传递方式、寄存器的使用方式以及栈的使用方式。
以Windows操作系统为例,Windows API使用的是stdcall调用约定,即参数从右往左依次压入栈中,返回值放在EAX寄存器中。
因此,我们需要在编写汇编函数时遵循这个调用约定。
下面是一个使用汇编语言实现计算阶乘的例子:```global factorial ; 导出函数符号section .textfactorial:push ebp ; 保存调用函数的栈帧指针 mov ebp, esp ; 设置当前栈帧指针mov eax, [ebp+8] ; 获取函数参数cmp eax, 1 ; 判断参数是否为1jle .base_case ; 如果是,则返回1dec eax ; 否则,计算(n-1)!push eax ; 保存(n-1)的值call factorial ; 递归调用阶乘函数pop ecx ; 恢复(n-1)的值imul eax, ecx ; 计算n*(n-1)!jmp .done ; 返回结果.base_case:mov eax, 1 ; 如果参数为1,则返回1.done:mov esp, ebp ; 恢复栈指针pop ebp ; 恢复调用函数的栈帧指针 ret ; 返回函数结果```在这个例子中,我们定义了一个名为“factorial”的函数,该函数计算输入参数的阶乘。
Keil软件“C语言”与“汇编”混编相关知识整理用Keil在C中嵌入汇编 (1)在Keil中嵌入汇编 (2)介绍直接嵌入汇编代码的方法 (4)采用汇编可能会有的好处 (5)Keil C语言与汇编语言混合编程 (7)深入剖析Keil C51 ——从汇编到C51 (9)C语言和汇编语言的变量以及函数的接口问题 (14)汇编与C语言混合编程的关键问题 (15)KEIL段重定位 (15)用Keil在C中嵌入汇编早前公布了C和汇编混编的温度控制器程序,收到一些朋友的询问,他们无法在自己程序中使用我的18B20的汇编子程序或无法正常通过混编后的程序编译。
其实在KEIL中嵌入汇编的方法很简单。
如图一,在C文件中要嵌入汇编的地方用#pragma asm和#pragma endasm 分隔开来,这样编译时KEIL就知道这中间的一段是汇编了。
图1在有加入汇编的文件中,还要设置编译该文件时的选项图2Generate Assembler SRC File 生成汇编SRC文件Assemble SRC File 封装汇编文件(如图三的状态为选中)选上这两项就可以在C中嵌人汇编了,设置后在文件图示中多了三个红色的小方块。
图3为了能对汇编进行封装还要在项目中加入相应的封装库文件,在笔者的项目中编译模式是小模式所以选用C51S.LIB。
这也是最常用的。
这些库文件是中KEIL安装目录下的LIB目录中。
加好后就可以顺利编译了。
(注:我只在7.0以上版本使用过)图4在Keil中嵌入汇编1、其实在KEIL中嵌入汇编的方法很简单。
如图1,在C文件中要嵌入汇编的地方用#pragma as m和#pragma endasm分隔开来,这样编译时KEIL就知道这中间的一段是汇编了。
2、在有加入汇编的文件中,还要设置编译该文件时的选项,如图2所示。
3、Generate Assembler SRC File 生成汇编SRC文件Assemble SRC File 封装汇编文件(如图3的状态为选中)选上这两项就可以在C中嵌人汇编了,设置后在文件图示中多了三个红色的小方块。
3.4.2 在汇编程序中调用C函数从汇编程序中调用C语言函数的方法实际上在上面已经给出。
在上面C语言例子对应的汇编程序代码中,我们可以看出汇编程序语句是如何调用swap()函数的。
现在我们对调用方法作一总结。
在汇编程序调用一个C函数时,程序需要首先按照逆向顺序把函数参数压入栈中,即函数最后(最右边的)一个参数先入栈,而最左边的第1个参数在最后调用指令之前入栈,如图3-6所示。
然后执行CALL 指令去执行被调用的函数。
在调用函数返回后,程序需要再把先前压入栈中的函数参数清除掉。
调用函数时压入堆栈的参数在执行CALL指令时,CPU会把CALL指令的下一条指令的地址压入栈中(见图3-6中的EIP)。
如果调用还涉及代码特权级变化,那么CPU会进行堆栈切换,并且把当前堆栈指针、段描述符和调用参数压入新堆栈中。
由于Linux内核中只使用中断门和陷阱门方式处理特权级变化时的调用情况,并没有使用CALL指令来处理特权级变化的情况,因此这里对特权级变化时的CALL指令使用方式不再进行说明。
汇编中调用C函数比较"自由",只要是在栈中适当位置的内容就都可以作为参数供C函数使用。
这里仍然以图3-6中具有3个参数的函数调用为例,如果我们没有专门为调用函数func()压入参数就直接调用它的话,那么func()函数仍然会把存放EIP位置以上的栈中其他内容作为自己的参数使用。
如果我们为调用func()而仅仅明确地压入了第1、第2个参数,那么func()函数的第3个参数p3就会直接使用p2前的栈中内容。
在Linux 0.1x内核代码中就有几处使用了这种方式。
例如在kernel/sys_call.s汇编程序中第231行上调用copy_process()函数(kernel/fork.c中第68行)的情况。
在汇编程序函数_sys_fork中虽然只把5个参数压入了栈中,但是copy_process()却带有多达17个参数(见下面的程序)。
keil C语言与汇编语言混合编程1. C语言中嵌入汇编1、在C 文件中要嵌入汇编代码片以如下方式加入汇编代码:#pragma ASM; Assembler Code Here#pragma ENDASM2、在Project 窗口中包含汇编代码的C 文件上右键,选择“Options for ...”,点击右边的“Generate Assembler SRC File”和“Assemble SRC File”,使检查框由灰色变成黑色(有效)状态;3、根据选择的编译模式,把相应的库文件(如Small 模式时,是Keil\C51\Lib\C51S.Lib)加入工程中, 该文件必须作为工程的最后文件;4、编译,即可生成目标代码。
来个实例吧:#i nclude <reg51.h>{P2=1;#pragma asmMOV R7,#10DEL:MOV R6,#20DJNZ R6,$DJNZ R7,DEL#pragma endasmP2=0;}2 . 无参数传递的函数调用1.无参数传递的函数调用先来个例子:其中example.c和example.a51为项目中的两个文件***********************example.c*********************************************** extern void delay100();main(){delay100;}***********************example.a51*********************************************** ?PR?DELAY100 SEGMENT CODE; // 在程序存储区中定义段PUBLIC DELAY100; //声明函数RSEG ?PR?DELAY100; //函数可被连接器放置在任何地方DELAY100/P>MOV R7,#10DEL:MOV R6,#20DJNZ R6,$DJNZ R7,DELRETEND在example.c文件中,先声明外部函数,然后直接在main中调用即可。
浅谈单⽚机中C语⾔与汇编语⾔的转换⼀、单⽚机课设题⽬要求与软件环境介绍做了⼀单⽚机设计,要⽤C语⾔与汇编语⾔同时实现,现将这次设计的感受和收获,还有遇到的问题写下,欢迎感兴趣的朋友交流想法,提出建议。
单⽚机设计:基于51单⽚机的99码表设计软件环境:Proteus8.0 + Keil4要求:1,开关按⼀下,数码管开始计时。
2,按两下,数码管显⽰静⽌。
3,按三下,数码管数值清零。
⼆、C语⾔程序1 #include<reg51.h>2#define uint unsigned int3#define uchar unsigned char4 uchar shi,ge,aa,keycount=0,temp;5 sbit anjian=P1^7;6 uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};7void display(shi,ge);8void key ();9void init();10void delay(uint z);11/*-----主程序-----*/12void main()13 {14 init(); //初始化15while(1)16 {17 key ();18if(keycount==1)19 TR0=1; //开中断20if(keycount==2)21 TR0=0;22if(keycount==3)23 {24 temp=0;25 keycount=0;26 }27if(aa==10){aa=0;28if(temp<=99)29 {30 temp++;display(shi,ge);31 }32else33 temp=0;}34 }35 }363738/*------初始化程序-------*/39void init()40 {41 keycount=0;42 temp=0;43 TMOD=0x01;44 TH0=(65536-50000)/256;45 TL0=(65536-50000)%256;46 EA=1;47 ET0=1;48//TR0=0;49 }50/*-----定时器中断-----*/51void timer0() interrupt 152 {53 TH0=(65536-50000)/256;54 TL0=(65536-50000)%256;55 aa++;56 }57/*-----显⽰⼦程序-----*/58void display(shi,ge)59 {60 shi=temp/10;61 ge=temp%10;62 P0=table[shi];;delay(70);63 P2=table[ge]; ;delay(70);64 }65/*-----按键检测⼦程序-----*/66void key ()67 {68if(anjian==0)69 {70 delay(5); //消抖71if(anjian==0)72 keycount++;73 }74//while(anjian==0);75//display(shi,ge); //等待按键弹起76 }77/*-----延时⼦程序-----*/78void delay(uint z) //延时约1ms79 {80uint x,y;81for(x=z;x>0;x--)82for(y=100;y>0;y--);83 }电路仿真结果如下:三、C语⾔转汇编语⾔步骤好了,那么接下来我们就开始C语⾔——>汇编语⾔之旅(1)C语⾔1-10⾏改为1 ORG 0000H //汇编起始伪指令,功能是规定程序存储器中源程序或数据块存放的起始地址2 ajmp STAR //ajmp⽆条件跳转指令3 ORG 000bh4 ajmp timer05 anjian equ P1.7 //位定义6 keycount equ 40h7 shi equ 41h8 gewei equ 42h9 aa equ 43h10 temp equ 44h11tab: db 3fh,6h,5bh,4fh,66h //建表12 db 6dh,7dh,7h,7fh,6fh(2)C语⾔中的初始化函数 12-14⾏和39-49⾏改为1STAR:2 acall init //⼦程序近程调⽤指令,功能是主程序调⽤⼦程序,调⽤⼦程序的范围为2kb1init:2mov keycount,#0 //keycount=03mov temp,#0 //temp=14mov tmod,#01h //TMOD=0x015mov TH0,#606mov TL0,#1767setb EA //位置位指令,对操作数所指出的位进⾏置1操作8setb ET09setb TR010retacall为⼦程序近程调⽤指令,返回⽤ret。
c语言直接调用汇编函数C语言作为一种高级语言,它的代码比汇编语言更容易阅读和理解。
但是在一些需要最大化性能的场合,我们需要使用汇编语言编写低级代码来达到最优性能。
这时,可以通过c语言直接调用汇编函数来解决问题。
一、汇编函数调用格式1.汇编函数需要使用global指令将该函数声明为全局变量,使c语言中的程序可以使用汇编函数。
2.如下所示是一个简单的汇编函数,功能是求两个整数之和:global _Add_Add:mov eax,[esp+4] ;1.将第一个参数传入eax寄存器add eax,[esp+8] ;2.将第二个参数加到eax中ret ;3.返回计算结果3.在c语言程序中,可以使用以下代码调用该汇编函数:int Add(int a, int b) {int result;__asm {mov eax, amov ebx, bcall _Add ;直接调用汇编函数_Addmov result, eax ;将返回值保存到result中}return result;}二、汇编函数调用过程分析1.在c语言程序中,调用_complement函数。
2.编译器将调用_add函数的指令转换为汇编代码,包含将两个参数传递到Add函数中的语句和对_Add函数的调用语句。
该代码被插入到c 语言程序的代码中,正确地传递两个参数到汇编代码中。
3.汇编代码执行所需要的寄存器的状态在调用之前就已经被保存在栈中。
当_add函数执行完毕并返回结果时,它将计算结果存储在eax寄存器中。
4.返回值从汇编代码中流回到c语言的Add函数中,并且被存储于result变量中。
5.返回到c语言程序执行下一条指令,并返回计算结果。
三、注意事项1.汇编函数需要声明为全局变量,使用global指示C编译器在可执行文件中导出该函数的符号。
2.汇编函数的签名必须与c语言函数的签名相同或相似,如返回类型和参数的数量/类型/顺序必须一致。
3.在汇编函数中,必须保证调用函数前和返回函数时,所有寄存器的状态和堆栈指针(rp)的状态都应该与c代码中调用函数的状态一致。
KEILC51中C语言加入汇编语言的使用方法一、为什么使用汇编语言?汇编语言是一种底层的编程语言,其主要目的是实现对硬件的直接控制,具有高度灵活性和效率。
在开发单片机程序时,通常使用高级语言来编写大部分的代码,但是在一些特定的情况下,使用汇编语言能够更好地满足需求,例如对一些硬件寄存器的操作、实现高速计算等。
二、C语言与汇编语言相结合的方法在KEILC51中,可以通过使用内联汇编或者使用汇编模块的方式将C 语言与汇编语言相结合。
1.内联汇编内联汇编是将汇编代码直接嵌入到C语言代码中。
使用内联汇编可以获得更高的性能和灵活性,但也增加了代码的可读性和可维护性。
在C语言中使用内联汇编需要使用__asm关键字,并在括号中编写要嵌入的汇编代码。
以下是一个示例:```void delay(unsigned int count)__asmMOVR1,loop:INCR1CJNE R1, count, loop}```在上述示例中,使用了__asm关键字将一段简单的汇编代码嵌入到了C函数delay中,以实现一个延时功能。
2.汇编模块另一种将C语言与汇编语言相结合的方法是使用汇编模块。
汇编模块是一个独立的文件,其中包含了汇编语言代码。
可以通过使用extern关键字将C语言代码与汇编模块连接起来。
首先,需要创建一个汇编模块的文件,例如delay.asm,其中包含了要实现的汇编代码:```; delay.asmPUBLIC delaydelay PROCMOVR1,loop:INCR1CJNE R1, R2, loopRETdelay ENDP```在上述示例中,创建了一个名为delay的汇编函数,该函数实现了一个简单的延时功能。
接下来,在C语言代码中使用extern关键字声明要调用的汇编函数:```// main.cextern void delay(unsigned int count);void maindelay(1000);```在上述示例中,使用extern关键字声明了一个名为delay的汇编函数。