汇编语言中的子程序调用参数的传送方式有哪些
简单点说,call指令在跳转前保存当前指令地址,而jmp一类的指令不保存当前指令的地址。
详细点说:
call指令在跳转前会在栈中保存当前的程序计数器(IP)的值(有必要的话还要保存CS),保存完IP的值后,再去执行跳转指令。即相当于:
push CS (没有这种指令,有没有这一句还要看调用的类型:far/near)
push IP (没有这种指令)
jmp [word ptr/dword ptr] ...
这样,程序在执行ret/retf指令时就能从栈中取出IP的值,即相当于:
pop IP (没有这种指令)
pop CS (没有这种指令,有没有这一句也要看调用的类型)
来继续执行call指令后的其他指令,当然你也可以选择不执行ret,而把call当做jmp来用。这样也没有问题(没人这么干),只不过栈里多了点东西罢了,记得处理就好。
而形如jmp一类的指令只是简单的执行跳转(修改IP的值),并不保存IP的值。当然跳转后程序也就不知道原来是从哪里跳转到这里来的,自然就无法返回。
当然,这个时候ret指令还是可以用的,因为ret指令只是简单的从栈顶取出一个word然后赋给IP,所以也可以用ret指令来实现jmp的功能(也没人这么干)。如:
mov bx,offset s
push bx
ret
这样就相当于:
jmp s
所以说不要只是记一个指令怎么用,而是要理解一个指令到底是什么原理。
C语言与汇编语言混合编程应遵守的规则
ARM编程中使用的C语言是标准C语言,ARM的开发环境实际上就是嵌入了一个C语言的集成开发环境,只不过这个开发环境与ARM的硬件紧密相关。
在使用C语言时,要用到和汇编语言的混合编程。若汇编代码较为简洁,则可使用直接内嵌汇编的方法;否则要将汇编程序以文件的形式加入到项目中,按照ATPCS(ARM/Thumb过程调用标准,ARM/Thumb Procedure 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);
}
}
1)寄存器传递法:适用于参数少时。
2)变量传递法:适用于同一源文件(程序模块)中。
3)堆栈传递法:只适用于传递入口参数。
这个看个人习惯,有的用R0~R7,有的用累加器。还有的用其他寄存器。
Fortran 模块(Module), 参数共享、共享
在编程语言Fortran中,子程序和自定义函数被广泛使用来简化大型程序的编写,使得代码更容易阅读和调试。在程序结构中,子程序和自定义函数各自拥有独立的变量声明。这意味着,在主程序和子程序,或者不同子程序之间,即使变量名相同,它们也互不影响。调用子程序时涉及参数传递,Fortran采用传址调用。这意味...
汇编和c语言如何结合的?
为此,必须了解各种语言的堆栈结构、生成方式和入栈方式等。C语言与汇编语言的接口可以分为两种情况:一种是C语言调用汇编子程序,另一种是C语言嵌入汇编。在C程序中使用关键字"ExTERn"对函数作显式说明,参数传递顺序是按其在参数表中出现的顺序的反序被压入堆栈中。对不同的存储模式,要选用不同的...
call函数是什么
具体来说,`call`函数可以用于以下情况:1. 调用其他函数:通过使用`call`函数,可以在程序中调用其他已定义的函数,并传递所需的参数。这样可以在需要的时候执行特定的功能代码。2. 执行子程序:在某些编程语言中,`call`函数也可以用于执行子程序或子例程。子程序是一系列执行特定任务的代码段,通过`...
易语言 调用子程序传参问题
跟你传入参数有关系把,你子程序接受一个参数是整数型,但是你启动时传入的参数是{0,0,0,0} 我建议你直接先创建一个变量,然后把变量赋值为{0,0,0,0},然后调试这个变量,看看显示是什么
易语言子程序、参数和变量什么意思啊?
假设 执行该命令 子程序1("传送的数据")--- .子程序 子程序1 .参数 参数1, 文本型 信息框 (参数1, 0, )那么信息框会输出 传输的数据.这就是参数的作用.那么当你看完上面的方法后,下面我们来举一个算数例子..子程序 加法运算 .参数 参数1, 整数型 .参数 参数2, 整数型 .局部变量 结果...
c语言函数调用时,参数是如何传递的
建立中间变量(形参),把实参值赋值给中间变量,当被调函数返回值时,系统释放掉中间变量。在程序中通过对函数的调用来执行函数体,其过程与其它语言的子程序调用相似。对无参函数调用时则无实际参数表。实际参数表中的参数可以是常数、变量或其它构造类型数据及表达式。各实参之间用逗号分隔。函数作为...
子程序调用是什么意思?
子程序调用在很多编程语言中都存在,如C、C++、Java、Python等等。不同语言的实现方式可能不同,但本质是相同的。子程序调用通常需要使用特定的语法来调用,同时还需要遵循一定的调用过程和参数传递方式。一般来说,子程序被调用之后会返回一个值,这个返回值可以通过特定的方式被主程序获取,以便主程序进行...
c语言 调用函数是实参是计算好再赋值给形参还是把实参的数直接赋值给...
函数的参数调用和传递是这样的:调用子程序或函数 参数顺序(一般是倒序)压入堆栈:如果是数据,直接压栈;如果是表达式,求取其值后将值压栈;变量则将其值取出压栈 进入子程序,子程序分配存放在堆栈中的各数据以临时变量名,这些变量名就是函数头部的参数名,子程序中用这些临时变量名进行运算 如果...
8086汇编语言段间和段内,SP分别加多少
段内调用子程序时,栈顶的1个字保存的是返回的ip,传递的参数 的sp要多加2。段间调用子程序时,栈顶的2个字分别保存了返回的ip和cs,传递参数时的sp要多加4。但不会用sp+2、sp+4这种格式,而是在进入子程序时,先将当前sp保存到bp中,用bp作为基点获得传递的参数,因为sp总是在变化之中。
FORTRAN 中怎么实现不同文件之间的子程序调用? 是用外部程序吗?
此外,确保两个文件正确地包含在同一个项目中,是保证跨文件调用成功的关键。通过项目管理工具,可以方便地将文件加入到项目中,并设置编译选项,以支持跨文件的子程序调用。这样做不仅可以避免编译错误,还能确保程序的正确执行。值得注意的是,FORTRAN语言本身并不直接支持跨文件的子程序调用,这需要借助于...