L12D10 伪操作与混合编程

一、伪操作

(一)微操作的概念

伪指令:本身不是指令,编译器可以将其替换成若干条指令

伪操作:不会生成代码,只是在编译阶段告诉编译器怎么编译

(二)C语言中的伪操作

在C语言中一般带‘ ;’是可以编译的指令,带‘ # ’的是预编译指令,是伪指令,预处理时处理,不会编译,不会生成汇编代码。例如

#define PI 3.14

#if --- #endif

(三)汇编中的伪操作

汇编代码中的伪操作一般都以‘ . ’开头

1、声明全局变量

.global symbol

将symbol声明成一个全局变量

未声明不能引用:

声明后引用:

2、声明局部变量

.local symblo

将symbol声明成一个局部变量

3、宏定义

.equ DATA,0xFF

MOV R1,#DATA 

相当于C语言中的宏定义

4、封装代码

.macro FUNC 
   
   MOV R1,#1
   MOV R2,#2
  
.endm
  
   FUNC 

 5、条件编译

#if 1

MOV R1,#1
MOV R2,#2

#endif

#if 0

MOV R1,#1
MOV R2,#2

#endif

 6、重复语句

.rept 3

 MOV R1,#1
 MOV R2,#2

.endr

 7、弱化一个符号

如果程序执行一个没有定义的符号,使用.weak修饰可以通过编译,但这条指令会变成一条NOP空指令

@.weak symbol

.weak func
B func

8、申请空间

在当前地址申请一个字的空间并将其初始化

MOV R1,#1
.word 0xFFFFFFFF
MOV R2,#2

 9、按2的n次对齐操作

.align 2

@数字的含义是按2的几次方对齐

10、 申请任意n个字节的内存地址空间

.space 12,0x12

 11、其他常见的伪操作

.text
@进入代码段
.end
@结束代码段

 指令集:

.arm
@下面执行的都是arm指令
.thumb
@下面执行的都是thumb指令

 汇编指令集取决于处理器,而伪操作取决于编译器,不同编译器伪操作语法不同,本节我们使用的是GNU编译器,因此伪操作的语法和GNU编译器相对应。

二、C和汇编混合编程

(一)背景知识

操作系统的作用:向下管理硬件、向上提供接口(API)。

 驱动是在操作系统层次。

数据处理指令、跳转指令、内存访问指令是通用指令,任何一个处理器都具备这些通用指令,通用指令一般在C语言中都有相应的语句对应。

状态寄存器传送指令(读写CPSR),软中断(系统调用)、协处理器指令,是专用指令,ARM有其他处理器不一定有。

在ARM处理器上装Linux操作系统,当linux操作系统要进行软中断等专用指令时(内核代码),C语言没有对用的指令,此时使用C语言和汇编指令混合编程,能用C的用C。

所有的CPU都离不开汇编语言。所有CPU在刚上电时的代码都是汇编语言。C语言直接使用栈,在这之前要初始化SP,单片机之前的启动代码都是汇编语言。初始化栈和CPU模式都要通过汇编指令。

(二)C和汇编混合编程格式

1、汇编语言调用(跳转)C语言

在CPU上电完成后,需要跳转到C语言。

arm-asm.s

MOV R1,#1
MOV R2,#2
BL func_c
MOV R3,#3

test.s
func_c(void){
int a;
a++;
a--;
}

 执行到第三行时自动跳转:

2、C语言调用(跳转)汇编语言

arm-asm.s

       MOV R1,#1
       MOV R2,#2
       BL func_c

.global FUNC_ASM
FUNC_ASM:
       MOV R4,#4
       MOV R5,#5


test.s

func_c(void){
int a = 1;
FUNC_ASM();
}

3、C内联汇编

func_c(void){
int a = 1;
asm
(

"MOV R1,#1\n"
"MOV R2,#2\n"

);

a++;

}

4、C语言和汇编混合编程的原则

在哪种语言环境下符合哪种语言的语法规则

1)在汇编中,将C语言当做标号来处理

2)在C语言中将汇编语言的编号当做函数来处理

三、ATPCS协议

(一)背景知识

混合编程时,我们自己写的栈有可能会库函数的栈有冲突(压栈出栈方式、方向)。又或者我们写的C语言编译和库函数的编译方式也不同,可能会导致内存覆盖。

ATPCS协议用于规定不同编译器编译出来的代码怎么做到兼容。

ATPCS:arm thumb program call(调用) standard

(二)ATPCS协议的内容

1、栈的种类

使用满减栈

2、寄存器的使用

R15(LR):程序计数器,只能用于存储程序的指针,不能用于其他用途

R14(PC):链接寄存器,只能用于返回地址,不能用作其他用途

R13(SP):栈指针,只能用于存储栈指针,不能用于其他用途(实际上我们就是在ATPCS协议规定下将R13当作栈指针)

R0-R3:当函数的参数少于4个的时候使用R0-R3,多出的4个部分用栈传递。

main向其他函数传参时,函数会从R0-R3依次读取第一个参数、第二个参数、第三个参数...

多余4个的参数压入栈中,函数直接从栈中去拿。因此在写代码时,能少于4个参数,就少于4个参数。

3、返回值

返回值使用R0回传。

int a,b,c,d,e,f,g;
func_c(int a,int b,int c, int d,int e,int f){
return a+b+c+d+e+f;
}
int main(){

g = func_c(a,b,c,d,e,f);
}

4、其余的寄存器用于存储局部变量。

四、ARM体系结构总结

1、操作系统的作用

向下管理硬件,向上提供接口,研究操作系统就是研究底层,直接对接CPU和其他硬件设备。

2、ARM的多种模式主要是为了适应操作系统的需求。

3、栈的效率比堆要高。

4、系统调用的内涵,应用调用write()函数,需要到操作系统调用Liunx的一些机制,此时需要更高权限的模式,所以进行软中断,CPU从用户模式到SVC模式。

5、通过汇编知道C语言代码在实际CPU中是怎样执行的。越高级的语言用起来越方便,越偏离原理。C语言就是在汇编之上进行封装。可以去写Linux下的一些应用程序。shell脚本是shell去封装C,不需要关心内存。

6、驱动方向->Device control

五、作业
1.简述ATPCS协议的主要内容是什么

ATPCS规定了应用程序的函数可以如何分开地写,分开地编译,最后将它们连接在一起,所以它实际上定义了一套有关过程(函数)调用者与被调用者之间的协议。PCS强制实现如下约定:调用函数如何传递参数(即压栈方法,以何种方式存放参数),被调用函数如何获取参数,以何种方式传递函数返回值。
1、栈的种类
使用满减栈
2、寄存器的使用
R15(LR):程序计数器,只能用于存储程序的指针,不能用于其他用途
R14(PC):链接寄存器,只能用于返回地址,不能用作其他用途
R13(SP):栈指针,只能用于存储栈指针,不能用于其他用途(实际上我们就是在ATPCS协议规定下将R13当作栈指针)
R0-R3:当函数的参数少于4个的时候使用R0-R3,多出的4个部分用栈传递。
main向其他函数传参时,函数会从R0-R3依次读取第一个参数、第二个参数、第三个参数...
多余4个的参数压入栈中,函数直接从栈中去拿。因此在写代码时,能少于4个参数,就少于4个参数。
3、返回值
返回值使用R0回传。
4、其余的寄存器用于存储局部变量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值