C语言与汇编语言混合编程_32位嵌入式共6页word资料

合集下载

嵌入式Linux下C和汇编的混合编程

嵌入式Linux下C和汇编的混合编程

2.6 嵌入式Linux下C和汇编的混合编程2.6.1 混合编程概述2.6.1.1 C和汇编的混合编程及类型C语言是被称为高级的低级语言,原因是在C语言中,有许多针对硬件的操作,能很好地利用硬件特性。

从一方面来说,C语言也是高级语言,它能很方便地实现各种复杂的编程算法。

在嵌入式系统编程中,C语言是首选的程序设计语言,但在某些特定条件下,C语言无法精确地操作硬件,此时往往采用嵌入或调用汇编程序的方法来解决此类问题。

这就是混合编程。

混合编程从方式上主要包括三类,即:C程序调用汇编程序;汇编程序调用C程序;C程序内嵌汇编。

本文后续将分别介绍这三类编程方法。

2.6.1.2 ATPCS规范简介基于ARM的嵌入式C和汇编的混合编程需要遵循一定的规范,这就是过程调用标准ATPCS 规范。

ATPCS规定了子程序间相互调用的基本规则,调用过程中寄存器的使用规则、数据栈的使用规则及参数的传递规则。

2007年,ARM公司推出了新的过程调用标准AAPCS(ARM Architecture Produce Call Standard),它只是改进了原有的ATPCS的二进制代码的兼容性。

这里简单介绍寄存器的使用规则、数据栈的使用规则、参数的传递规则和子程序结果返回规则,更详细的内容请参考其它参考资料。

1. 寄存器使用规则●子程序间通过寄存器R0~R3传递参数,寄存器R0~R3可记作A1~A4。

被调用的子程序在返回前无须恢复寄存器R0~R3的内容。

●在子程序中,ARM状态下使用寄存器R4~R11来保存局部变量,寄存器R4~R11可记作V1~V8;Thumb状态下只能使用R4~R7来保存局部变量。

●寄存器R12用作子程序间调用时临时保存栈指针,函数返回时使用该寄存器进行出栈,记作IP;在子程序间的链接代码中常有这种使用规则。

●通用寄存器R13用作数据栈指针,记作SP。

●通用寄存器R14用作链接寄存器。

●通用寄存器R15用作程序计数器,记作PC 。

汇编语言与C的混合编程PPT教学课件

汇编语言与C的混合编程PPT教学课件
• 第1个寄存器列表中的寄存器用于存放输入的参数。 • 第2个寄存器列表中的寄存器用于存放返回的结果。 • 第3个寄存器列表中的寄存器的内容可能被所调用
的子程序破坏,即这些寄存器是供所调用的子程 序作为工作寄存器的。
2020/12/10
9
2内嵌的汇编器和armasm的区别
• 与armasm相比,内嵌的汇编器在功能和使用方法上主要 有以下特点:
开成几条指令。例如指令: • ADD R0,R0,#1023 • 可能会被展开成下面的指令序列 • ADD R0,R0,#1024 • SUB R0,R0,#01 • 乘法指令MUL可能会被展开成一系列的加法操作和移位操作。 • 事实上,除了与协处理器相关的指令外,大部分的ARM指令和
Thumb指令中包含常量操作数都可能被展开成多条指令。
器的值,用户不需要去保护和恢复这些寄存器的值。
• 用户可以改变处理器模式,但是编译器并不了解处理器模式的改变。 这样,如果用户改变了处理器模式,将不能使用原来的C表达式;重 新恢复到原来的处理器模式后,才能再使用这些C表达式。
2020/12/10
11
3在C程序中使用内嵌的汇编指令
• 3.1在C程序中使用内嵌的汇编指令的语法格式 • 在ARM C语言程序中使用关键词_asm来标识一段汇编指令程序,其格式如下: • _asm •{ • Instruction[;instruction] • …… • [instruction] •} • 其中,如果一行中有很多个汇编指令,则指令之间使用分号“;”隔开。如
• 通常推荐在内嵌的汇编指令中不要指定物理寄存器,因为这可能会影 响编译器分配寄存器,进而可能影响代码的效率。
2020/12/10
4
1.3常量

嵌入式实验(汇编和C语言混合编程实验)

嵌入式实验(汇编和C语言混合编程实验)

嵌入式实验(汇编和C语言混合编程实验)汇编和C语言混合编程实验7.1实验目的①掌握C程序中内嵌指令的使用方法。

②理解汇编程序调用C程序函数和变量的方法。

7.2 实验环境①硬件:PC机②软件:ADS1.27.3 实验内容①使用内嵌汇编的方法设计允许和禁止中断程序。

②验证汇编程序调用C程序函数和访问C程序变量的执行过程。

7.4 实验过程1、实验7-1 允许和禁止中断程序本实验使用内嵌汇编的方法完成允许和禁止中断程序设计,这里使用Armulator 作为调试的目标机。

(1)新建ARM工程exp7_1启动ADS开发环境,选择File→New(Project)选项,使用ARM Executable Image工程模板创建一个工程exp5_1.(2) 新建汇编程序文件exp7_1_1.c,并将其添加到工程exp7_1中选择File→New(File)选项,新建汇编源程序文件exp7_1_1.c并添加到工程exp7_1中,exp7_1_1.c源程序的参考代码如下: #include__inline void enable_IRQ(void) {int tmp;__asm {MRS tmp, CPSRBIC tmp, tmp, #0x80 MSR CPSR_c, tmp } }__inline void disable_IRQ(void) {int tmp; __asm{MRS tmp, CPSR ORR tmp, tmp, #0x80 MSR CPSR_c, tmp } }int main(void) {enable_IRQ( ); disable_IRQ( ); return 0;}(3) 设置工程exp7_1的编译和链接选项选择Edit→DebugRel Settings选项,打开DebugRel Settings对话框,设置工程编译和链接选项,在Language Settings→ARM Assembler选项中,选择Target选项卡,修改处理器类型为ARM920T. (4) 编译和链接工程在工程exp7_1窗口中,选择Make工具按钮,编译和链接工程exp7_1,如果有错误提示,请检查修改程序中的语法错误,直到编译和链接通过。

C语言第7讲嵌入式C与汇编语言混合编程

C语言第7讲嵌入式C与汇编语言混合编程

7.1 内嵌汇编器的使用
在C/C++程序中使用内嵌的汇编指令注意事项 程序中使用内嵌的汇编指令注意事项

对于内嵌汇编器可能会用到的寄存器, 对于内嵌汇编器可能会用到的寄存器,编译器自己会保存 和恢复这些寄存器,用户不用保存和恢复这些寄存器。 和恢复这些寄存器,用户不用保存和恢复这些寄存器。常 量寄存器CPSR和寄存器 和寄存器SPSR外,别的寄存器必须先赋值 量寄存器 和寄存器 外 然后再读取,否则编译器将会报错。如下例中, 然后再读取,否则编译器将会报错。如下例中,第一条指 令在没有给寄存器r0赋值前读取其值 是错误的; 赋值前读取其值, 令在没有给寄存器 赋值前读取其值,是错误的;最后一 条指令恢复寄存器r0的值 的值, 条指令恢复寄存器 的值,也是没有必要的
7.1 内嵌汇编器的使用
内嵌的汇编器和armasm的区别 的区别 内嵌的汇编器和
使用内嵌的 汇编器不能 通过寄存器 PC返回当前 返回当前 指令的地址
内嵌的汇编器不 支持伪指令LDR 支持伪指令 Rn,=expression可 可 以使用mov来代替 以使用 来代替
不支持标号 表达式
不支持ADR、 、 不支持 ADRL 伪指令
7.1 内嵌汇编器的使用
内嵌的汇编指令用法——标号 标号 内嵌的汇编指令用法
C/C++程序中的标号可以被内嵌的汇编指令使用。但 程序中的标号可以被内嵌的汇编指令使用。 程序中的标号可以被内嵌的汇编指令使用 是只有指令B可以使用 可以使用C/C++程序中的标号,指令 程序中的标号, 是只有指令 可以使用 程序中的标号 指令BL 不能使用C/C++程序中的标号。指令 使用 程序中的标号。 使用C/C++程 不能使用 程序中的标号 指令B使用 程 序中的标号时,语法格式如下所示: 序中的标号时,语法格式如下所示:

汇编语言与C的混合编程

汇编语言与C的混合编程

1.3常量
• 在内嵌的汇编指令中,常量前的符号#可以省略。如果在一个表达式 前使用#,则该表达式必须是一个#。 • 1.4指令展开 • 内嵌的汇编指令中如果包含常量操作数,则该指令可能会被汇编器展 开成几条指令。例如指令: • ADD R0,R0,#1023 • 可能会被展开成下面的指令序列 • ADD R0,R0,#1024 • SUB R0,R0,#01 • 乘法指令MUL可能会被展开成一系列的加法操作和移位操作。 • 事实上,除了与协处理器相关的指令外,大部分的ARM指令和 Thumb指令中包含常量操作数都可能被展开成多条指令。
1.2物理寄存器
• 在内嵌的汇编指令中使用物理寄存器有一下限制: • 不能直接向PC寄存器中赋值,程序的跳转只能通过B指令和BL指令实 现。 • 在使用物理寄存器的内嵌汇编指令中,不要使用过于复杂的C表达式, 因为当表达式过于复杂时,将会需要较多的物理寄存器,这些寄存器 可能与指令中的物理寄存器的使用冲突。 • 编译器可能会使用R1寄存器或者R13寄存器存放编译的中间结果,在 计算表达式值时可能会将寄存器R0~R3、R2以及R14用于子程序的调 用。因此在内嵌的汇编指令中,不要将这些寄存器同时指定为指令中 的物理寄存器。 • 在内嵌的汇编指令中使用物理寄存器时,如果有C变量使用了该物理 寄存器,编译器将在合适的时候保存并恢复该变量的值。需要注意的 是,当寄存器sp、sl、fp以及sb用做特定的用途时,编译器不能恢复 这些寄存器的值。 • 通常推荐在内嵌的汇编指令中不要指定物理寄存器,因为这可能会影 响编译器分配寄存器,进而可能影响代码的效率。
• 下面是一个在汇编程序中访问C程序全局变量的例子。程序中变量 globv1是在C程序中声明的全局变量。在汇编程序中首先使用 IMPORT伪操作声明该变量;R0中;修改后再将寄存器R0的值赋予变量 globv1.本例中程序如下: • AREA globals,CODE,READONLY • EXPORT asmsub • IMPORT global ;用IMPORT伪指令声明该变量 • asmsum • LDR R1,# globv1 ;将其内存地址读入到寄存器R1中 • LDR R0,[R1] ;再将其值读入到寄存器R0中 • ADD R0,R0,#2 • STR R0,[R1] ;修改后再将寄存器R0的值赋予变量globv1 • MOV PC,LR • END

C语言与汇编语言混合编程

C语言与汇编语言混合编程
1. 基本ATPCS 基本ATPCS规定了在子程序调用是的一些基本规 则,包括下面3方面的内容:
1) 各寄存器的使用规则及其相应的名称。 2) 数据栈的使用规则。 3) 参数传递的规则。
相对于其他类型的ATPCS, 满足ATPCS的程序的 执行速度更快,所占用的内存更少,但是它不能提供以 下的支持:ARM程序和Thumb程序相互调用、数据以 及代码的位置无关的支持、子程序的可重入性和数据 栈检查的支持。
途。 3.参数传递规则 根据参数个数是否固定可以将子程序分为参数
个数固定的子程序和参数个数可变的子程序。 (1)参数个数可变的子程序参数传递规则
对于参数个数可变的子程序,当参数个数不超
过4个时,可以使用寄存器R0~R3来传递参数,当参 数超过4个时,还可以使用数据栈来传递参数。 (2)参数个数固定的子程序参数传递规则
❖ 结果为一个64位整数时,可以通过寄存器R0和R1 返回,依次类推。
❖ 结果为一个浮点数时,可以通过浮点运算部件的寄 存器f0、d0或者s0来返回。
❖ 结果为复合型的浮点数时,可以通过寄存器f0~fN或 者d0~dN来返回。
❖ 对于位数更多的结果,需要通过内存来传递。
对有调用关系的所有子程序必须遵守同一种 ATPCS。
嵌入式系统设计与开发
C语言与汇编语言混合编程
1.1 C程序与汇编程序互相调用规则 1.2 内嵌汇编程序设计 1.3 C语言函数和ARM汇编语言函数间互相调用
C语言与汇编语言混合编程
1.1 C程序与汇编程序互相调用规则 为了使单独编译的C语言程序和汇编程序之间能
够相互调用,必须让子程序间的调用遵循一定的规则。 ATPCS即ARM,Thumb过程调用标准,是ARM程序和 Thumb程序中子程序调用的基本规则,它规定了一些子 程序间调用的基本规则。下面介绍几种ATPCS规则:

C与汇编混合编程_

C与汇编混合编程_

C与汇编语言混合编程⏹嵌入式C语言程序设计技巧⏹C与汇编语言混合编程⏹嵌入式C语言程序构架位运算⏹位运算⏹C语言中位运算符有:⏹按位求反~①按位与&③⏹左移<<②按位异或^④⏹右移>>②按位或|⑤⏹(圆圈中的数字表示运算符的优先级)⏹扩展运算符包括:<<=、>>=、&=、^=、|=。

⏹位运算的实质是对字节或字中的实际位进行检测、设置或移位,它只适用于字符型和整数型变量以及它们的变体,对其它数据类型不适用。

⏹移位运算:⏹右移:变量名>>移位的位数⏹左移:变量名<<移位的位数⏹讨论位运算符和逻辑运算符的不同。

嵌入式系统总是要用户对变量或寄存器进行位操作。

给定一个整型变量a,写两段代码,第一个设置a的bit3,第二个清除a的bit3。

在以上两个操作中,要保持其它位不变。

位操作(Bit manipulation)#define BIT3(0x1<<3)static int a;void set_bit3(void){a|=BIT3;}void clear_bit3(void){a&=~BIT3;}变量修饰符⏹volatile—易失性修饰符,说明所定义的变量或指针,是可以被多种原因修改的.⏹一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。

精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。

下面是volatile变量的几个例子:⏹1)存储器映射的硬件寄存器(如:状态寄存器)⏹2)一个中断服务子程序中会访问到的非自动变量(Non-automaticvariables)⏹3)多线程应用中被几个任务共享的变量⏹volatile定义寄存器⏹C语言中绝对地址0x1D30000只被当做整数,做为地址时要强制转换,如:⏹int*p;p=(*int)0x1D30000;//定义44b0中与看门狗相关的寄存器地址#define rWTCON(*(volatile unsigned*)0x1D30000)#define rWTDAT(*(volatile unsigned*)0x1D30004)#define rWTCNT(*(volatile unsigned*)0x1D30008)⏹硬件端口寄存器读取问题⏹char x=0,y=0,z=0;⏹x=readChar(0x54000000);⏹y=x;⏹x=readChar(0x54000000);⏹z=x;⏹很可能被编译器优化为:⏹char x=0,y=0,z=0;⏹x=readChar(0x54000000);⏹y=x;⏹z=x;⏹嵌入式C语言程序设计技巧⏹C与汇编语言混合编程⏹嵌入式C语言程序构架C语言与汇编语言混合编程⏹C语言和ARM汇编语言程序间相互调用1.汇编代码访问全局C变量2.C程序调用汇编程序3.汇编程序调用C程序⏹在C程序和ARM汇编程序之间相互调用必须遵守ATPCS.C语言与汇编语言混合编程⏹ATPCS介绍⏹ATPCS(ARM-Thumb Produce call Standard)是ARM程序和Thumb程序中子程序调用的基本规则,目的是为了使单独编译的C语言程序和汇编语言程序之间能够相互调用.⏹基本ATPCS规定了在子程序调用时的一些基本规则,包括:各寄存器的使用规则及其相应的名称,堆栈的使用规则,参数传送的规则.C语言与汇编语言混合编程⏹1.寄存器的使用规则⏹子程序间通过寄存器R0-R3来传递参数.⏹在子程序中,使用寄存器R4-R11来保存局部变量.⏹寄存器R12用作子程序间的scratch寄存器,IP.⏹寄存器R13用作数据栈指针,SP.⏹寄存器R14称为链接寄存器,LR.⏹寄存器R15是程序计数器,PC.⏹2.数据栈的使用规则⏹根据堆栈指针指向位置的不同和增长方向的不同可以分为以下4种数据栈:⏹FD(Full Descending)满递减⏹ED(Empty Descending)空递减⏹FA(Full Ascending)满递增⏹EA(Empty Ascending)空递增⏹ATPCS规定数据栈为FD(满递减)类型,并且对数据栈的操作是8字节对齐的。

汇编语言和C语言的混合编程

汇编语言和C语言的混合编程

2. 在汇编中使用C定义的全局变量
#include <stdio.h> int gVar_1 = 12; extern asmDouble(void);
int main() { printf("original value of gVar_1 is: %d", gVar_1); asmDouble(); printf(" modified value of gVar_1 is: %d", gVar_1); return 0; }
内嵌汇编使用的标记是 __asm,用法如下: __asm { instruction [; instruction] … [instruction] }
void enable_IRQ(void) { void disable_IRQ(void) {
int tmp;
__asm
int tmp;
__asm
PRESERVE8 AREA Scopy ,CODE,READONLY EXPORT strcopy strcopy LDRB R2,[R1],#1 STRB R2,[R0],#1 CMP R2,0 BNE strcopy MOV pc,lr END
在汇编中调用C的函数
• 在汇编中调用C的函数,需要在汇编中IMPORT 对应 的C函数名,使用BL指令调用
return a + b + c;
}
int g( int a, int b, int c, int d, int e, int f ) { printf(“e=%d\n”, e); printf(“f=%d\n”, f); return (a+b+c+d+e+f); }
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验二C语言与汇编语言混合编程
一、实验目的
1.掌握ARM嵌入式C语言编程基本方法。

2. 掌握嵌入式汇编(Inline Assembly)编程规则和方法。

3.掌握汇编语言程序和C语言程序之间相互调用规则和编程方法。

二、实验步骤
1. 创建工作空间并且添加工程。

2.编写程序并且利用软件仿真查看结果。

三、实验内容
1.利用汇编语言编写初始化程序,实现管理模式下堆栈指针初始化,
并最终跳转到C语言程序开始Main函数处执行。

2.利用汇编语言编写子程序实现字符串拷贝功能,利用C语言在
Main函数中定义字符串“Hello World!”定义并调用该子程序完成字符串拷贝。

3.利用汇编语言编写子程序完成冒泡法排序,利用C语言在Main
函数中定义字符串“Hello World!”定义并调用该子程序将数组中字符按照ASCII码值由小到大重新排序。

思考:
1.GNU编译环境下混合编程与ADS环境下有些什么区别?
.global _start
.global str_cpy
.text
_start:
BIC R0,R0,#MODEMASK @将CPSR中的模式位
ORR R1,R0,#FIQMODE @设置模式位为FIQ模式
MSR CPSR_c, R1 @切换处理器到FIQ模式
LDR SP,=FIQStack @设置该模式下的堆栈
BIC R0,R0,#MODEMASK @将CPSR中的模式位
ORR R1,R0,#IRQMODE @设置模式位为IRQ
MSR CPSR_c, R1 @切换处理器到IRQ模式
LDR SP,=IRQStack @设置该模式下的堆栈
BIC R0,R0,#MODEMASK @将CPSR中的模式位
ORR R1,R0,#USRMODE @设置模式位为IRQ
MSR CPSR_c, R1 @切换处理器到IRQ模式
LDR SP,=IRQStack @设置该模式下的堆栈
BL Main
B .
.equ FIQMODE,0x11
.equ IRQMODE,0x12
.equ SVCMODE,0x13
.equ USRMODE,0x10
.equ SVCStack,0x03FE0100
.equ FIQStack,0x03FE0200
.equ IRQStack,0x03FE0300
.equ MODEMASK,0x1F
str_cpy:
LDRB R2,[R0],#1
STRB R2,[R1],#1
CMP R2,#0
BNE str_cpy
MOV PC,R14
.end
extern void str_cpy(char *x,char *y);
int Main()
char *a="Hello World!\n";
char b[13];
str_cpy(a,b);
return 0;
.global _start
.global str_cpy
.global line
.text
_start:
BIC R0,R0,#MODEMASK @将CPSR中的模式位
ORR R1,R0,#FIQMODE @设置模式位为FIQ模式
MSR CPSR_c, R1 @切换处理器到FIQ模式
LDR SP,=FIQStack @设置该模式下的堆栈
BIC R0,R0,#MODEMASK @将CPSR中的模式位
ORR R1,R0,#IRQMODE @设置模式位为IRQ
MSR CPSR_c, R1 @切换处理器到IRQ模式
LDR SP,=IRQStack @设置该模式下的堆栈
BIC R0,R0,#MODEMASK @将CPSR中的模式位
ORR R1,R0,#USRMODE @设置模式位为IRQ
MSR CPSR_c, R1 @切换处理器到IRQ模式
LDR SP,=IRQStack @设置该模式下的堆栈
BL Main
B .
.equ FIQMODE,0x11
.equ IRQMODE,0x12
.equ SVCMODE,0x13
.equ USRMODE,0x10
.equ SVCStack,0x03FE0100
.equ FIQStack,0x03FE0200
.equ IRQStack,0x03FE0300
.equ MODEMASK,0x1F
str_cpy:
ldrb r2,[r0],#1
strb r2,[r1],#1
cmp r2,#0
bne str_cpy
mov pc,r14 line: mov r4,r0
add r5,r4,#1
mov r6,#12 loop1: mov r0,r4
mov r1,r5 loop:
ldrb r2,[r0]
ldrb r3,[r1]
cmp r3,#0x0a
beq ends
cmp r2,r3
strhib r3,[r0],#1
strhib r2,[r1],#1
addls r0,r0,#1
addls r1,r1,#1
b loop ends: subs r6,r6,#1
bne loop1
mov pc,r14
.end。

相关文档
最新文档