C中嵌入汇编程序的方法
- 格式:doc
- 大小:28.50 KB
- 文档页数:5
keilC中嵌入汇编程序的方法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、这点也是本人要重要说明的!即一定要将c:\keil\C51下的STARTUP.A51文件加入项目4、编译,即可生成目标代码。
来个实例吧:#i ncludevoid main(void){P2=1;#pragma asmMOV R7,#10DEL:MOV R6,#20DJNZ R6,$DJNZ R7,DEL#pragma endasmP2=0;}2 . 无参数传递的函数调用C51调用汇编函数1.无参数传递的函数调用先来个例子:其中example.c和example.a51为项目中的两个文件***********************example.c***************************** ******************extern void delay100();main(){delay100;}***********************example.a51*************************** ********************PR?DELAY100 SEGMENT CODE; // 在程序存储区中定义段PUBLIC DELAY100; //声明函数RSEG ?PR?DELAY100; //函数可被连接器放置在任何地方DELAY100:MOV R7,#10DEL:MOV R6,#20DJNZ R6,$DJNZ R7,DELRETEND在example.c文件中,先声明外部函数,然后直接在main中调用即可。
【转】C语言内嵌汇编(asm)TIPS:在编译过程汇中,汇编代码块是原封不动地送到汇编语言编译阶段的。
一、为什么会用到汇编?1.为了提高速度和效率。
不过这种情况很少了,现在C/C++编译器的优化很厉害了。
2.为了实现某些C语言中不具备、但为不同的机器所特有的功能。
这是主要原因。
为了利用通用的汇编语言例程。
也常会遇到。
二、何时使用汇编?第一种情况是,绝对没有其他方法可以使用。
第二种情况出现在某个C语言程序的执行时间必须减少的时候。
三、如何嵌入汇编?Turbo C :1.使用预处理程序的伪指令#asm和#endasm,#asm用来开始一个汇编程序块,而#endasm指令用于该块的结束。
例:代码:mul(a,b)int a,b;{#asmmov ax,word ptr 8[bp]imul ax word ptr 10[bp]#endasm}2.使用asm语句格式:asm<汇编语句>代码:mul(a,b)int a,b;{asm mov ax,word ptr 8[bp]asm imul ax word ptr 10[bp]}注意:asm行后面没有分号Visual C++ :格式:__asm 汇编指令 [ ; ]__asm { 汇编指令 } [ ; ]asm前面是两条下划线,后面的方括号内容表示分号可有可无。
使用方法:一条一条地用代码:__asm mov al, 2__asm mov dx, 0xD007__asm out dx, al组成一块地用代码:__asm {mov al, 2mov dx, 0xD007out dx, al}还可以弄成一条代码:__asm mov al, 2 __asm mov dx, 0xD007 __asm out dx, al msdn里面的内容:代码:/* POWER2.C */#include <stdio.h>int power2( int num, int power );void main( void ){printf( "3 times 2 to the power of 5 is %d/n", power2( 3, 5) );}int power2( int num, int power ){__asm{mov eax, num ; Get first argumentmov ecx, power ; Get second argumentshl eax, cl ; EAX = EAX * ( 2 to the power of CL )}/* Return with result in EAX */}GNU GCC :用到的关键字“__asm__”表示后面的代码为内嵌汇编,“asm”是“__asm__”的别名。
C语⾔内嵌汇编(内联汇编)###刷贴⼦发现⼀篇讲内联汇编的,果断收藏,备⽤。
###原贴地址:https:///wujianyongw4/article/details/80667965在内嵌汇编中,可以将C语⾔表达式指定为汇编指令的操作数,⽽且不⽤去管如何将C语⾔表达式的值读⼊哪个寄存器,以及如何将计算结果写回C 变量,你只要告诉程序中C语⾔表达式与汇编指令操作数之间的对应关系即可, GCC会⾃动插⼊代码完成必要的操作。
1、简单的内嵌汇编例:__asm__ __volatile__("hlt"); "__asm__"表⽰后⾯的代码为内嵌汇编,"asm"是"__asm__"的别名。
"__volatile__"表⽰编译器不要优化代码,后⾯的指令保留原样,"volatile"是它的别名。
括号⾥⾯是汇编指令。
2、内嵌汇编举例使⽤内嵌汇编,要先编写汇编指令模板,然后将C语⾔表达式与指令的操作数相关联,并告诉GCC对这些操作有哪些限制条件。
例如在下⾯的汇编语句:__asm__ __violate__ ("movl %1,%0" : "=r" (result) : "m" (input));"movl %1,%0"是指令模板;"%0"和"%1"代表指令的操作数,称为占位符,内嵌汇编靠它们将C 语⾔表达式与指令操作数相对应。
指令模板后⾯⽤⼩括号括起来的是C语⾔表达式,本例中只有两个:"result"和"input",他们按照出现的顺序分别与指令操作数"%0","%1"对应;注意对应顺序:第⼀个C 表达式对应"%0";第⼆个表达式对应"%1",依次类推,操作数⾄多有10 个,分别⽤"%0","%1"...."%9"表⽰。
C语言的嵌入式汇编为了使C语言程序具有更高的效率和更多的功能,需在C语言程序里嵌入用汇编语言编写的子程序。
一方面是为提高子程序的执行速度和效率;另一方面,可解决某些用C语言程序无法实现的机器语言操作。
而C语言代码与汇编语言代码的接口是任何C编译器毋庸置疑要解决的问题。
通常,有两种方法可将汇编语言代码与C语言代码联合在一起。
一种是把独立的汇编语言程序用C函数连接起来,通过API (Application Program Interface) 的方式调用;另一种就是我们下面要讲的在线汇编方法,即将直接插入式汇编指令嵌入到C函数中。
编译器GCC认可的基本数据类型及其值域列示在表4.8中。
采用GCC规定的在线汇编指令格式进行指令的输入,是GCC实现将µ’nSP™汇编指令嵌入C函数中的方法。
GCC在线汇编指令格式规定如下:asm (“汇编指令模板”:输出参数:输入参数:clobbers参数);若无clobber参数,则在线汇编指令格式可简化为:asm (“汇编指令模板”:输出参数:输入参数);下面,将对在线汇编指令格式中的各种成分之内容进行介绍。
1) 汇编指令模板模板是在线汇编指令中的主要成分,GCC据此可在当前位置产生汇编指令输出。
例如,下面一条在线汇编指令:asm ("%0 += %1" : "+r" (foo) : "r" (bar));此处,"%0 += %1"就是模板。
其中,操作数"%0"、"%1"作为一种形式参数,分别会由第一个冒号后面实际的输出、输入参数取代。
带百分号的数字表示的是第一个冒号后参数的序号。
如下例:asm ("%0 = %1 + %2" : "=r" (foo) : "r" (bar), "i" (10));"%0"会由参数foo取代,"%1"会由参数bar取代,而"%2"则会由数值10取代。
C语⾔中嵌⼊汇编(转)格式: _asm_("asm statements":outputs:inputs:registers-modified)其中,"asm statements"是汇编语句表达式,outputs,inputs,register-modified都是可选参数,以冒号隔开,且⼀次以0~9编号,如outputs 的寄存器是0号,inputs寄存器是1号,往后依次类推。
outputs是汇编语句执⾏完后输出到的寄存器,inputs是输⼊到某个寄存器。
例1:_asm_("pushl %%eax\n\t" "movl $0,%%eax\n\t" "popl %%eax");在嵌⼊汇编中,寄存器前⾯要加两个%,因为gcc在编译是,会先去掉⼀个%再输出成汇编格式。
例2:{ register char _res;\asm("push %%fs\n\t""movw %%ax,%%fs\n\t""movb %%fs:%1,%%al\n\t""pop %%fs":"=a"(_res):"0"(seg),"m"(*(addr)));\_res;}movb %%fs:%1,%%al\n\t⼀句中是把以fs为段地址,以后⾯的第⼆号寄存器即后⾯的seg中的值为偏移地址所对应的值装⼊al。
"=a"(_res):"0"(seg),"m"(*(addr)))⼀句中,"=a"(_res)表⽰把a寄存器中的内容给_res,"0"(seg)表⽰把seg中的内容给0所对应的寄存器,⽽0即表⽰使⽤和前⼀个寄存器相同的寄存器,这⾥即使⽤a寄存器,也就是说把seg中的内容个a寄存器。
在vc中嵌入汇编语言的方法一、内联汇编的优缺点因为在Visual C++中使用内联汇编不需要额外的编译器和联接器,且可以处理Visual C++中不能处理的一些事情,而且可以使用在C/C++中的变量,所以非常方便。
内联汇编主要用于如下场合:1.使用汇编语言写函数;2.对速度要求非常高的代码;3.设备驱动程序中直接访问硬件;4."Naked" Call的初始化和结束代码。
//(."Naked",理解了意思,但是不知道怎么翻译^_^,大概就是不需要C/C++的编译器(自作聪明)生成的函数初始化和收尾代码,请参看MSDN的"Naked <I>function</I>s"的说明)内联汇编代码不易于移植,如果你的程序打算在不同类型的机器(比如x86和Alpha)上运行,应当尽量避免使用内联汇编。
这时候你可以使用MASM,因为MASM支持更方便的的宏指令和数据指示符。
二、内联汇编关键字在Visual C++使用内联汇编用到的是__asm关键字,这个关键字有两种使用方法:1.简单__asm块__asm{MOV AL, 2MOV DX, 0xD007OUT AL, DX}2.在每条汇编指令之前加__asm关键字__asm MOV AL, 2__asm MOV DX, 0xD007__asm OUT AL, DX因为__asm关键字是语句分隔符,因此你可以把汇编指令放在同一行:__asm MOV AL, 2 __asm MOV DX, 0XD007 __asm OUT AL, DX显然,第一种方法和C/C++的风格很一致,并且有很多其它优点,因此推荐使用第一种方法。
不象在C/C++中的"{}",__asm块的"{}"不会影响C/C++变量的作用范围。
同时,__asm块可以嵌套,嵌套也不会影响变量的作用范围。
C语言与汇编语言相互结合的嵌套汇编语言
在单片机学习的过程中,掌握一点汇编语言是非常有必有的,作为低级语言汇编语言在单片机开发中有它不可取代的作用,比如每条指令可以精确的确定延时时间,便于理解非常适合硬件工程师学习。
但是要提高单片机技能,必须掌握 C 语言编程,因为 C 语言有强大的模块化管理思想。
我想在很多人学习的过程中即学了汇编语言,又学习了C 语言,那么一个问题便随之而产生,如果将C 语言与汇编语言相互结合,达到更好的编程效果,本次讲解就是基于这个问题而生成的。
大家可以看到,我的延时函数用的汇编。
然而编译后无法创建目标。
此时大家右键左边的工作组1:Source Group 1。
然后点击第一个OpTIons for Group Source Group 1。
将对话框右边红圈内两个选项各点两次,使对勾成为黑色。
点击OK后就可以编译了。
如果大家在编译时出现两个警告:
警告内容如下:
*** WARNING L1:UNRESOLVED EXTERNAL SYMBOL
SYMBOL:?C_START
MODULE:STARTUP.obj (?C_STARTUP)
*** WARNING L2:REFERENCE MADE TO UNRESOLVED EXTERNAL SYMBOL:?C_START
MODULE:STARTUP.obj (?C_STARTUP)
ADDRESS:0038H。
嵌入式系统设计
实验报告
实验名称:C程序中内嵌ARM汇编
姓名:冯玉平
学号:1203210014
班级:计研12
一、实验内容:
在C程序中内嵌ARM汇编,实现1+2+……+100,并在C 程序中将结果输出到屏幕上。
二、实验目的:
熟悉ADS操作坏境,学习ARM汇编程序,会在C程序中内嵌ARM汇编。
三、调试环境、器材:
器材:X86电脑一台,easyarm7实验板一个
环境:ADS
四、实验步骤:
1、打开ADS坏境,建立工程
2、建立一个文本文件,编写程序后保存,添加文件到工程
3、编译连接,修改调试程序
4、运行程序。
五、实验程序及结果:
程序:
#include<stdio.h>
int armasm(int sum,int i)
{
__asm
{
start:
MOV sum,#0;
MOV i,#100;
addnum:
ADD sum,sum,i;
SUBS i,i,#1;
BNE addnum;
}
return sum;
}
int main()
{
int c_i=0;
int c_sum=0;
c_sum=armasm(c_sum,c_i);
printf("c_sum = %d\n",c_sum);
}
结果:
c_sum = 5050
六、心得体会
1、文件要保存到相应的工程目录下
2、编写程序过程注意使用正确的书写格式
3、实验结果要对照程序是否一致,不一致要修改调试
4、认真,细心,多动手,多编写程序。
c 内嵌汇编格式在C语言中,可以使用内嵌汇编(Inline Assembly)来直接在C 代码中插入汇编代码。
内嵌汇编的格式如下:c复制代码asm (汇编语句);其中,汇编语句是你要插入的汇编代码。
例如,以下是一个简单的内嵌汇编示例,用于将一个整数变量x 的值加1:c复制代码int x = 5;asm ("addl $1, %0" : "=r"(x) :"0"(x));在这个示例中,addl $1, %0是一条汇编指令,用于将%0所指向的寄存器中的值加1。
: "=r"(x)表示将x的值存储到一个通用寄存器中,"0"(x)表示将x的值作为输入。
需要注意的是,内嵌汇编的语法和格式可能会因编译器和目标架构的不同而有所差异。
因此,在使用内嵌汇编时,需要仔细阅读你所使用的编译器的文档,并确保你的汇编代码与目标架构兼容。
在使用内嵌汇编时,需要注意以下几个方面:1.寄存器的使用:内嵌汇编允许你在代码中直接操作寄存器,因此需要了解目标架构中可用的寄存器以及它们的用途。
在某些架构中,寄存器的名称和数量可能因编译器或目标架构的不同而有所差异。
2.操作数的类型和大小:在汇编语言中,操作数的类型和大小是非常重要的。
例如,加法指令在不同的数据类型上可能有不同的行为。
因此,你需要确保你的汇编代码与C语言代码中的数据类型和大小相匹配。
3.内存操作数的使用:如果你在内嵌汇编中需要操作内存中的数据,需要使用操作数来指定内存地址。
在这种情况下,你需要确保内存地址是有效的,并且确保你的汇编代码不会导致访问违规或段错误等问题。
4.输入和输出操作数的约束:在内嵌汇编中,你需要使用约束来指定输入和输出操作数的位置和类型。
例如,你可以使用"=r"约束来指定一个通用寄存器作为输出操作数,使用"r"约束来指定一个通用寄存器作为输入操作数。
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、这点也是本人要重要说明的!即一定要将c:\keil\C51下的STARTUP.A51文件加入项目4、编译,即可生成目标代码。
来个实例吧:#i nclude <reg51.h>void main(void){P2=1;#pragma asmMOV R7,#10DEL:MOV R6,#20DJNZ R6,$DJNZ R7,DEL#pragma endasmP2=0;}2 . 无参数传递的函数调用C51调用汇编函数1.无参数传递的函数调用先来个例子:其中example.c和example.a51为项目中的两个文件***********************example.c************************************* **********extern void delay100();main(){delay100;}***********************example.a51*********************************** ************?PR?DELAY100 SEGMENT CODE; // 在程序存储区中定义段PUBLIC DELAY100; //声明函数RSEG ?PR?DELAY100; //函数可被连接器放置在任何地方DELAY100:MOV R7,#10DEL:MOV R6,#20DJNZ R6,$DJNZ R7,DELRETEND在example.c文件中,先声明外部函数,然后直接在main中调用即可。
在example.a51中,?PR?DELAY100 SEGMENT CODE; 作用是在程序存储区中定义段,DELAY100为段名,?PR?表示段位于程序存储区内PUBLIC DELAY100; 作用是声明函数为公共函数RSEG ?PR?DELAY100; 表示函数可被连接器放置在任何地方,RSEG是段名的属性段名的开头为PR,是为了和C51内部命名转换兼容,命名转换规律如下:CODE -?PR?XDATA-?XDDATA-?DTBIT-?BIPDATA-?PD3. 有参数传递的函数调用在写这片文章之前,写了个试验程序,但总是通不过,查看汇编代码发现c文件中的语句根本没有被编译进去,怎么也找不到原因,郁闷~~最后在网上搜了个试验程序,把我的程序复制过去,可以编译成功,奇怪了,在我的project里就是不行,我注意到我的project编译后出现一条WARNING:*** WARNING L7: MODULE > MODULE: 8.obj (8)而同样的程序代码在另外一个project中没有WARNING,肯定是这条WARNING语句导致的,里面提到NAME,难道和名字有关,马上把A51文件改个名字(原来c文件和a51文件名字一样),编译,哈哈,WARNING不见了,查看汇编代码,一切按预想的进行,唉,一个名字害得我不浅啊,记住哦,c文件和A51文件不能使用同一个文件名,不过我还不知道为什么会这样,有高手知道得话请告知,还是进行今天的作业吧!今天说说带参数传递的函数调用,在C51和汇编之间传递参数的方式有两种,一种是通过寄存器传递参数,C51中不同类型的实参会存入相应的寄存器,在汇编中只需对相应寄存器进行操作,即达到传递参数的目的。
不同类型的数据及其传递参数的寄存器如下表所示:参数类型 char int long/float 通用指针第1个 R7 R6&R7 R4-R7 R1-R3第2个 R5 R4&R5 R4-R7 R1-R3第3个 R3 R2&R3 -- R1-R3举个例子吧,void delay(unsigned char i, unsigned int j) 当执行语句delay(10,1000)时,10会存入R7中,1000高位会存入R4中,低位存入R5中。
在汇编语句中从这几个寄存器中取数,再进行操作就行了,说起来也很简单的嘛,呵呵~来个最简单的实例吧,没什么意义,傻瓜式的程序:****************************main.c*********************************** **********extern void DELAY(unsigned char i,unsigned int j);main(){DELAY(10,1000);while(1);}**********************DELAY.A51************************************** ******?PR?_DELAY?DELAY SEGMENT CODEPUBLIC _DELAYRSEG ?PR?_DELAY?DELAY_DELAY:DJNZ R4,$DJNZ R5,$DJNZ R7,$RETEND还要说的是,函数名前要加下划线,表示是有参数传递的函数调用!4. 函数的返回值传递参数(2)函数返回值所用的寄存器返回值类型寄存器说明Bit C 由具体标志位返回char/unsigned char / 1 byte 指针 R7int/unsigned int / 2 byte 指针 R6&R7 高位在R6long/unsigned long / 3 byte 指针 R4-R7 高位在R4float R4-R7 32bit IEEE格式,指数和符号位在R7通用指针 R1-R3 存储类型在R3,高位在R2实例:********************main.c**************************************** unsigned int example(unsigned char i){return(i*i);}main(){example(80);#pragma asmDJNZ R7,$DJNZ R6,$#pragma endasmwhile(1);}函数返回值在R6,R7中。
有时候用到需要精确延时之类的子程序时,用C语言比较难控制,这时候就可以在C中嵌入汇编比较常用的keil中嵌入汇编的方法如下所示:如图一,在C文件中要嵌入汇编的地方用#pragma asm和#pragma endasm分隔开来,这样编译时KEIL就知道这中间的一段是汇编了。
在有加入汇编的文件中,还要设置编译该文件时的选项Generate Assembler SRC File 生成汇编SRC文件Assemble SRC File 封装汇编文件(如图三的状态为选中)选上这两项就可以在C中嵌人汇编了,设置后在文件图示中多了三个红色的小方块。
为了能对汇编进行封装还要在项目中加入相应的封装库文件,在笔者的项目中编译模式是小模式所以选用C51S.LIB。
这也是最常用的。
这些库文件是中KEIL安装目录下的LIB目录中。
加好后就可以顺利编译了。
(注:我只在7.0以上版本使用过)汇编与C语言混合编程的关键问题1 C程序变量与汇编程序变量的共用为了使程序更易于接口和维护,可以在汇编程序中引用与C程序共享的变量:.ref_to_dce_num,_to-dte_num,_to_dce_buff,_to_dte_buff 在汇编程序中引用而在C程序可直接定义的变量:unsigned char to_dte_buff[BUFF_SIZE]; //DSP发向PC机的数据 int to_dte_num; //缓冲区中存放的有效字节数int to_dte_store; //缓冲区的存放指针int to_dte_read; //缓冲区的读取指针这样经过链接就可以完成对应。
2 程序入口问题在C程序中,程序的入口是main()函数。
而在汇编程序中其入口由*.cmd文件中的命令决定,如:-e main_start;程序入口地址为 main_start。
这样,混合汇编出来的程序得不到正确结果。
因为C到ASM的汇编有默认的入口c-int00,从这开始的一段程序为C程序的运行做准备工作。
这些工作包括初始化变量、设置栈指针等,相当于系统壳不能跨越。
这时可在*.cmd文件中去掉语句:-e main_start。
如仍想执行某些汇编程序,可以C函数的形式执行,如:main_start(); //其中含有其他汇编程序但前提是在汇编程序中把_main_start作为首地址,程序以rete结尾(作为可调用的函数)的程序段,并在汇编程序中引用_main_start,即.ref _main_start。
3 移位问题在C语言中把变量设为char型时,它是8位的,但在DSP汇编中此变量仍被作为16位处理。
所以会出现在C程序中的移位结果与汇编程序移位结果不同的问题。
解决的办法是在C程序中,把移位结果再用0X00FF去“与”一下即可。
4 堆栈问题在汇编程序中对堆栈的依赖很小,但在C程序中分配局部变量、变量初始化、传递函数变量、保存函数返回地址、保护临时结果功能都是靠堆栈完成。
而C编译器无法检查程序运行时堆栈能否溢出。
5 程序跑飞问题编译后的C程序跑飞一般是对不存在的存储区访问造成的。
首先要查.MAP 文件与memory map图对比,看是否超出范围。
如果在有中断的程序中跑飞,应重点查在中断程序中是否对所用到的寄存器进行了压栈保护。
如果在中断程序中调用了C程序,则要查汇编后的C程序中是否用到了没有被保护的寄存器并提供保护(在C程序的编译中是不对A、B等寄存器进行保护的)。