C语言调用汇编语言时变量的传递

C语言调用汇编语言时变量的传递
C语言调用汇编语言时变量的传递

F2812中C语言调用汇编函数

参考资料:

(1) SPRU514 ---- TMS320F28x Optimizing C/C++ Compiler User’s Guide.pdf;

(2) spru430d ---- TMS320C28x DSP CPU and Instruction Set Reference Guide;

(3) spru513c ---- TMS320C28x Assembly Language Tools User's Guide.

一、编写C语言能调用的.asm文件

以delay.asm为例:

1、将文件保存为.asm文件;

2、在文件中编写如下代码:

;********************************************************** ***********/

;* 鲍正华*/

;* 2010.07.09 */

;********************************************************** ***********/

;//######################################################### ##################

; @FunctionName: Delay_asm

;

; @Brief: 延时1s

;

; @Param: unsigned long cnt 传给ACC

;

; @Return: 无

;//######################################################### ##################

.def _Delay_asm

.global _Delay_asm

.sect".delayasmpage"

_Delay_asm:

SUB ACC,#1 ;1 clk

BF _Delay_asm,GEQ ;4/4 clk, Loop if ACC >= 0

LRETR ;4 clk

;There is a 9/10 cycle overhead and each loop

;takes five cycles. The LoopCount is given by

;the following formula:

; DELAY_CPU_CYCLES = 9 + 5*LoopCount

; LoopCount = (DELAY_CPU_CYCLES - 9) / 5

; The macro DELAY_US(A) performs this calculation for you

;********************************************************** *************/

; No more

;********************************************************** *************/

3、在步骤2中:

.def _Delay_asm用来定义函数名;

.global _Delay_asm将函数名全局化,以便在C文件中能够调用;.sect".delayasmpage"将函数定位到定义的段中,也可以是.text,可以灵活运用;

_Delay_asm:为函数标号,注意一定在前面加上下划线_否则C文件不能调用;

LRETR是函数返回,采用了RPC时必须用该指令。

4、在C文件中对函数原型进行声明:

extern void Delay_asm(unsigned long cnt);

5、在C文件中以C语言形式调用汇编函数:

//延时1s

Delay_asm(18000000L);

6、上边的参数unsigned long cnt传递给了累加器ACC。

二、C语言调用汇编函数时的参数传递

参考(1) SPRU514 ---- TMS320F28x Optimizing C/C++ Compiler User’s Guide.pdf中的page168~169中的内容。

要点:

1、如果汇编语言中修改了XAR1、XAR2和XAR3的值,必须对它们进行保护:

;保存XAR1、XAR2、XAR3,以防程序修改, 若程序没有修改可以不用压栈保护

PUSH XAR1 ;1 clk

PUSH XAR2 ;1 clk

PUSH XAR3 ;1 clk

.

.

.

;恢复XAR1、XAR2、XAR3

POP XAR3 ;1 clk

POP XAR2 ;1 clk

POP XAR1 ;1 clk

2、16位参数从左至右依次传递给:AL、AH、XAR4、XAR5;

3、指针参数依次传递给:XAR

4、XAR5,其它指针参数放到stack 中;

4、32位的参数传递给累加器ACC(AH/AL),其它32位参数放到stack 中。

例子:

(1)汇编代码:

;//######################################################### ##################

; @FunctionName: _Xintf_memcpy_asm

;

; @Brief: copy指定xintf

;

; @Param: dest_addr, src_addr, length

;

; @Return: 无

;//######################################################### ##################

.def _Xintf_memcpy_asm ;函数定义

.global _Xintf_memcpy_asm ;函数全局声明,以便C能够调用

.sect".xintfmemcpyasmpage" ;以下为代码段

_Xintf_memcpy_asm: ;标号必须从第1列开始,而汇编语言助记符不能从第1列开始

;保存XAR1、XAR2、XAR3,以防程序修改, 若程序没有修改可以不用压栈保护

;PUSH XAR1 ;1 clk

;PUSH XAR2 ;1 clk

;PUSH XAR3 ;1 clk

;copy指定区域(从XAR4指定区域copy到XAR5指定区域)$1:

MOV AR6, *XAR5++ ;4 clk

MOV *XAR4++, AR6 ;1 clk

SUB ACC, #1 ;1 clk

BF $1, GT ;4/4 clk, 大于则跳转

;恢复XAR1、XAR2、XAR3

;POP XAR3 ;1 clk

;POP XAR2 ;1 clk

;POP XAR1 ;1 clk

LRETR ;4 clk, 程序返回

(2)C文件中对函数原型的声明:

extern void Xintf_memcpy_asm(unsigned int* dest_addr, unsigned int* src_addr, unsigned long length);

(3)C文件中以函数原型形式对汇编函数进行调用:

Xintf_memcpy_asm((unsigned int*)ZONE6ADDRESS, (unsigned

int*)ZONE2ADDRESS, 102400L);

(4)这里参数传递过程是:Z ONE6ADDR ESS传递给XAR4, ZONE2ADDRESS传递给XAR5, 102400L传递给ACC

参数传递方式

引用在函数参数传递中的作用 传递参数有三种方法:1,传递对象本身。2,传递指向对象的指针。3,传递对象的引用。 (1)传值方式 ①传给被调用函数的是整型、长整型、浮点型或双精度型变量。被调用的函数得定义相应的变量为形参。 ②传给被调用函数的是结构变量。被调用函数得定义结构变量为形参。 ③传给被调用函数的是结构变量的成员。被调用函数得定义与该成员同类的变量为形参。 #include "stdio.h" ?#include ?main( ) ?{ ?void swap(int pt1,int pt2); ?int a,b; ?scanf("%d, %d", &a,&b); ?swap(a,b); ?printf("\n%d,%d\n",a,b); ?} ?void swap(int pt1,int pt2) ?{int p; p=pt1; pt1=pt2; pt2=p; } ?

#include "stdio.h" void swapint(); int a,b; void main() { a = 5, b = 10; swapint(); printf("%d\n%d\n",a,b); } void swapint() { int temp; temp=a; a=b; b=temp; } (2)传址方式 ①传给被调用函数的是变量的地址。被调用函数得定义指针变量为形参。 ②传给被调用函数的是数组的地址即数组名。被调用的函数得定义数组或指针变量为形参。 ③传给被调用函数的是函数的地址即函数名称。被调用函数得定义指向函

数的指针变量为形参。④传给被调用函数的是结构的地址。被调用函数得定义结构指针为形参。 #include "stdio.h" ?#include ?main( ) ?{ ?void swap(int *pt1,int *pt2); ?int a,b,*p1,*p2; ?scanf("%d, %d", &a,&b); ?p1=&a;p2=&b; ?swap(p1,p2); ?printf("\n%d,%d\n",a,b); ?} ?void swap(int *pt1,int *pt2) ?{int p; p=*pt1; *pt1=*pt2; *pt2=p; } #include "stdio.h" void swapint(int *a,int *b); void main() { int a = 5, b = 10;

C语言与汇编语言互相调用

浅谈C程序中调用汇编模块的方法 C语言是目前非常流行的一种编程语言,除具有高级语言使用方便灵活、数据处理能力强、编程简单等优点外,还可实现汇编语言的大部分功能,如可直接对硬件进行操作、生成的目标代码质量较高且执行的速度较快等。所以在工程上对硬件处理速度要求不很高的情况下,基本可以用C代替汇编语言,编写接口电路的控制软件。但C也不能完全取代汇编语言,如在一些对速度要求很高的实时控制系统中,以及对硬件的特殊控制方面,C有时也不能完全很好胜任,还需要汇编语言来编写。因为汇编语言目标代码更精练,对硬件直接控制能力更强和执行速度更快,但汇编语言编程烦难、表达能力差也显而易见。比较好的解决办法是C与汇编语言混合编程,即用C编写软件的调度程序、用户界面以及速度要求不高的控制部分,而用汇编语言对速度敏感部分提供最高速度的处理模块,供C调用。这种方法提供了最佳的软件设计方案,做到了兼顾速度效率高和灵活方便。由于本人的毕业设计需要C 程序中调用汇编模块的方法来提高ARM定点指令的执行速度,故对这方面进行了学习。学习心得如下: 对于C和汇编语言的接口主要有两个问题需要解决。 一、调用者与被调用者的参数传递 这种数据传递通过堆栈完成,在执行调用时从调用程序参数表中的最后一个参数开始,自动依次压入堆栈;将所有参数压入堆栈后,再自动将被调用程序执行结束后的返回地址(断点)压入堆栈,以使被调程序结束后能返回主调程序的正确位置而继续执行。例如一调用名为add汇编程序模块的主函数:main( ){...... add(dest,op1,op2,flages);......}。在此例中对主函数进行反汇编,主函数在调用add函数前自动组织的堆栈。 . . . lea 0xfffffffe8(%ebp),%eax #flages数组的首地址入栈 push %eax pushl 0xfffffff8(%ebp) #OP2入栈 pushl 0xfffffffc(%ebp) #OP1 入栈 pushl 0xfffffff0(%ebp) #dest地址入栈 call 0x80483f0 #调用add函数 . . 执行完add调用语句后,栈内数据结果如图一所示。 进入汇编子程序后,为了能正确获取主调程序并存入堆栈中的数据,被调的汇编子程序先后要做如下一些工作: 1、保存esp的副本 进入汇编子程序后,子程序中免不了要有压栈和出栈的操作,故ESP时刻在变化。为了能用ESP访问堆栈中的参数,安全办法是一进入子程序后,先为ESP制副本,以后对传递参数的访问都用副本进行。一般可用EBP保存ESP,如: push %ebp mov %ebp,%esp

汇编错误总结

1、test.asm(54):error A2000:Block nesting error、 说明:此错误信息通常见于一个段定义起始段名和末尾段名不一 致。说明:此错误信息通常见于一个段定义起始段名和末尾段 名不一致。修改:检查段定义,使段名前后保持一致。修改: 检查段定义,使段名前后保持一致。 2、test.asm(5):error A2005:Symbol is multidefined:DATA 说明:符号重复定义了。说明:此错误信息提示DATA符号 重复定义了。修改:重新设置。修改:将其中一个符号DATA 重新设置。 3、test.asm(7):error A2009:Symbol not defined:B9H、 说明:行指令出错,查看该指令,说明:此错误信息为 test.asm中第7行指令出错,查看该指令,源操作数为十六 进制数B9H。按规定以字母开始的十六进制数,应在其。按规 定以字母开始的十六进制数,以便汇编程序区分常数和符号。 前面加上数字0以便汇编程序区分常数和符号。另一种出错的 可能原因是程序中使用的符号变量没有定义。能原因是程序中 使用的符号变量没有定义。修改:修改:以0B9H取代B9H; 使用伪指令定义变量。;使用伪指令定义变量。 4、test.asm(11):error A2009:Symbol not defined:NO、 说明:说明:test.asm中第11行指令JLE no-count,符号 中使用了中折线,中,符号中使用了中折线,折线在汇编中是 作为减号,因此,没有定义。折线在汇编中是作为减号,因此,汇编提示标号NO没有定义。注意,汇编语言规定符号中可以 使用下划线。注意,汇编语言规定符号中可以使用下划线。修 改:修改:将no-count改为no_count。。 5、test.asm(28):error A2010:Syntax error、

嵌入式简单汇编程序实例

ARM实验报告 姓名:郭健傧学号:L2101898 1.实验目的 (1)了解ADS1.2集成开发环境及ARMulator软件仿真; (2)熟悉ARM的乘法指令和逻辑指令; (3)结合ARM处理器硬件特性,比较处理函数的特性; 2.实验设备 硬件:pc机一台; 软件:Windowsxp系统,ADS1.2集成开发环境; 3.实验内容 (1)建立一个新的工程; (2)建立一个汇编文件,并添加到工程; (3)根据所给的两个C语言函数编写相应的汇编程序,并比较一下代码中fact1和fact2两个函数的特性; 4.实验步骤 (1)启动ADS1.2IDE集成开发环境,使用ARM Executable Image 工程模块建立一个工程heiye。 (2)建立汇编源文件test.s,编写程序实验,并添加到工程heiye中。 (3)设置工程连接地址Ro Base为0x40000000,RWBase为0x40003000。设置调试入口地址Image entry point为0x40000000。 (4)编译链接工程,并启动AXD进行软件仿真调试。 5.编写程序如下: C程序源代码: int fact1(int limit) { int fact=1; for(i=1;i

C#中方法的参数有四种类型

C#中方法的参数有四种类型 1. 值参数(不加任何修饰符,是默认的类型) 2. 引用型参数(以ref 修饰符声明) 3. 输出参数(以out 修饰符声明) 4. 数组型参数(以params 修饰符声明) 1. 值传递: 值类型是方法默认的参数类型,采用的是值拷贝的方式。也就是说,如果使用的是值类型,则可以在方法中更改该值,但当控制传递回调用过程时,不会保留更改的值。 使用值类型的例子如:(下面的Swap()未能实现交换的功能,因为控制传递回调用方时不保留更改的值) using System; class Test { static void Swap(int x, int y) { int temp = x; x = y; y = temp; } static void Main() { int i = 1, j = 2; Swap(i, j); Console.WriteLine("i = {0}, j = {1}", i, j); } } /* * 输出结果为: i=1, j=2 * 未能实现Swap()计划的功能 */ 2. 引用传递(ref类型) ref关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。 2.1. 若要使用ref 参数,则方法定义和调用方法都必须显式使用ref关键字。 2.2. 传递到ref 参数的参数必须最先初始化。这与out 不同,out 的参数在传递之前不需要显式初始化。 2.3. 如果一个方法采用ref 或out 参数,而另一个方法不采用这两类参数,则可以进行重载。

相关实例如下: using System; class Test { static void Swap(ref int x, ref int y) { int temp = x; x = y; y = temp; } static void Main() { int i = 1, j = 2; Swap(ref i, ref j); Console.WriteLine("i = {0}, j = {1}", i, j); } } /* * 引用类型实现了Swap()计划的功能: * 输出为: * i = 2, j =1 */ 3. 输出类型(out类型) out 关键字会导致参数通过引用来传递。这与ref 关键字类似。 与ref 的不同之处: 3.1. ref 要求变量必须在传递之前进行初始化,out 参数传递的变量不需要在传递之前进行初始化。 3.2. 尽管作为out 参数传递的变量不需要在传递之前进行初始化,但需要在调用方法初始化以便在方法返回之前赋值。 示例如下: using System; class Test { static void Swap(out int x, out int y) { //在这里进行了i和j的初始化

汇编语言出错信息说明

汇编程序出错信息说明 汇编程序出错信息 编 码 提示说明 0Block nesting error 嵌套过程、段、结构、宏指令、IRC、IRP或REPT不是正确结束,如嵌套的外层已终止,而内层还是打开状态。 1Extra characters on line 当一行上已接受了定义指令说明的足够信息,而又出现多余的字符。 2Register already defined汇编内部出现逻辑错误。 3Unknown symbol type 符号语句的类型字段中有些不能识别的东西。 4Redefinition of symbol在第二遍扫视时,连续地定义了一个符号。5Symbol is multi-defined重复定义一个符号。 6Phase error between passes 程序中有模棱两可的指令,以至于在汇编程序的两次扫视中,程序标号的位置在数值上改变了。 7Already had ELSE clause在ELSE从句中试图再定义ELSE语句。 8Not in conditional block 在没有提供条件汇编指令的情况下,指定了ENDIF或ELSE。 9Symbol not defined符号没有定义 10Syntax error语句的语法与任何可识别的语法不匹配11Type illegal in context指定的类型在长度上不可接收 12Should have been group name给出的组名不符合要求 13Must be declared in pass1得到的不是汇编程序所要求的常数值,例如:向前引用的长度 14Symbol type usage illegal PUBLIC符号的使用不合法 15Symbol already different kind 企图定义与以前定义不同的符号 16Symbol is reserved word企图非法使用一个汇编程序的保留字 17Forward reference is illegal向前引用必须是在第一遍扫视中定义过的 18Must be register 希望寄存器作为操作数,但用户提供的是符号而不是寄存器 19Wrong type of register 指定的寄存器类型并不是指令或伪操作所要求的,例如:ASSUME AX 20Must be segment or group希望给出段或组,而不是其它

汇编语言的过程调用与c语言的函数调用

姓名:孙贵森 学号: 汇编语言地过程调用,如果需要传递参数,一般有种方法,通过寄存器来“传递”,或是通过参数来传递.(还有将所有参数制成参数列表并压栈地传递方法,但较少用.)通过寄存器来“传递”,不是真正意义上地传递,其只不过是事先在几个有限地寄存器中设置相应地值后,再调用过程,过程再直接读取这些寄存器地内容.可想而知,此法犹如语言中地全局变量,极易感染.而如果通过参数来传递,又不得不面临手工维护堆栈框架( )地重担.堆栈框架动态地存放着参数、调用过程地返回地址、过程局部变量、过程内地压栈等内容,也是不好对付地.一般情况下,一个普通地过程可能如下编写:文档来自于网络搜索 , ..... 作为遵从调用约定()调用者,则需这样调用上述过程: ; ; ; , * ; 而如果遵从调用约定,则: , ...... , [ ] ; , [ ]; ...... * ; , , ; ...... , [ ]; , [ ]; , [ ; , [ ]; ...... , ; * ;

在被调用地过程内,分为种情况: . 无参数,也无局部变量 . 有参数 . 有局部变量 当无参数且无局部变量时,堆栈中只是保存语句地下一条语句地地址,可以很安全地返回.而当有参数,使用伪指令地接收参数地形式,则会自动生成正确地返回代码.而当有局部变量,使用伪指令来定义局部变量,也会自动地生成正确地返回代码.在将参数压栈时,仍需将其打包为位地,文档来自于网络搜索 ; , ; ; 另一选择是,将用作地变量声明为. ; ; 还有另一种方法,即,总是传递指针. ; (, ) , ; , , , , , [] , , [] 这种方法在保留了我们可以声明仅需地变量类型地同时,也确保位地方法正确压栈.语言中地每一个函数都是一个独立地代码块.一个函数地代码块是隐藏于函数内部地,不能被任何其它函数中地任何语句(除调用它地语句之外)所访问(例如,用语句跳转到另一个函数内部是不可能地).构成一个函数体地代码对程序地其它部分来说是隐蔽地,它既不能影响程序其它部分,也不受其它部分地影响.换言之,由于两个函数有不同地作用域,定义在

汇编语言上机操作

汇编语言上机操作 一、建立子文件夹 如:D:\hb\masm 二、复制相关文件 把masm.exe、link.exe、ml.exe三个文件复制到上述文件夹中。 三、进入DOS方式 开始/运行/cmd 当前提示符可能是: C:\documents and settings\administrator> 四、常用DOS操作命令 1、改变当前盘 输入d: 并回车,屏幕显示: D:\> 2、改变当前目录 1)进入下一级目录 D:\>cd hb 回车后,屏幕显示: D:\hb>cd masm 回车后,屏幕显示: E:\hb\masm> 问题:可以一次进入下面二级或多级目录吗? 2)返回上一级目录 D:\hb\masm>cd.. 回车后,屏幕显示: D:\hb\>cd.. 回车后,屏幕显示: D:\> 问题:可以直接返回根目录吗? D:\hb\masm>cd\ 回车后,屏幕显示: D:\> 3、显示当前目录容 D:\>dir /p 分页显示当前目录容 问题:如何显示d:\text中的容? D:\>dir d:\text↙ 4、DOS方式下如何运行程序? DOS方式下的可执行文件(即程序文件)扩展名为.exe或.,运行时只需要在系统提示符下输入文件主名即可。例如,有一个文件名为test.exe,存入在D:\hb\masm 中,运行时,可以这样做: D:\hb\masm>test↙ 五、汇编语言上机过程 1、编辑源程序 运行:edit 回车后,进入EDIT环境,输入完后存盘(file/save)并退出(file/exit)。

2、汇编 D:\hb\masm>masm add5.asm↙ 生成目标程序文件add5.obj。(如果有语法错误,会提示错误所在行号和错误类型)3、连接 D:\hb\masm>link add5↙ 生成可执行文件add5.exe。 六、DEBUG程序调用及汇编语言程序调试方法 调试程序DEBUG是DOS支持的又一种系统软件,主要用于汇编语言程序的调试。汇编和连接过程只能查出源程序的语法错误,不能查出功能上的错误和程序不完善的地方。DEBUG程序为用户提供多种命令,大致有:显示和修改寄存器和存贮单元的容;执行程序中任意一段或一条指令;汇编单条源语句和反汇编机器码指令;查找字符代码;端口的输入和输出;文件装入存和写入磁盘等。用户利用这些命令可以查出任何程序功能上的错误。下面说明DEBUG程序的启动方法和主要命令意义。 (一)DEBUG程序的启动 DEBUG程序有两种启动方法。DEBUG程序是在DOS盘上的一个独立的可执行程序(扩展名为.COM),所以,DEBUG程序的第一种启动方法就是把它看作和一般的可执行程序一样,只要打入DEBUG和回车键,就可以把它装入存。但是这样启动只把DEBUG 程序本身装入存并进入等待DEBUG命令状态,还没有把要调试的程序装入存。第二种启动DEBUG的程序的方法是一次相继装入DEBUG程序和要调试的程序。打入的命令格式如下: DEBUG[d:][path]filename[.ext][parml][parm2] 其中的Filename是要调试程序的文件名,可选项[d:][path]和[.ext]分别是要调试程序的所在盘符、路径和扩展名。可选项[parml]和[parm2]是DEBUG程序为要调试程序准备的参数(一般不用)。 例进入DEBUG程序并装入要调试程序。其操作如下: D:\hb\masm>DEBUG add5.exe (进入DEBUG,并装配add5.exe) 此时屏幕上出现一个短线,这表示可以使用DEBUG命令了。 如果启动DEBUG时没有指定要调试的文件名,则需要用N命令指定要调试的文件,再用L命令将其装入存。操作如下: D:\hb\masm>debug↙ - n add5.exe↙ - l↙ (二)DEBUG命令 在说明每个命令之前,先说明一些共同信息: ■DEBUG命令都是以一个英文字母开头,后面跟一个或多个参数。 ■命令字母和参数可用大写或小写或混合形式。 ■命令字母和参数中,相邻两个十六进制之间必须用逗号或空格分开.其它各部分之间有无空格或逗号都可以。 ■执行任何命令期间都可用Ctrl+Break键方法结束命令的执行。

汇编错误总结

1、test.asm(54): error A2000: Block nesting error 、 说明:此错误信息通常见于一个段定义起始段名和末尾段名不一 致。说明:此错误信息通常见于一个段定义起始段名和末尾段 名不一致。修改:检查段定义,使段名前后保持一致。修改: 检查段定义,使段名前后保持一致。 2、test.asm(5): error A2005: Symbol is multidefined: DATA 说明:符号重复定义了。说明:此错误信息提示 DATA 符号重 复定义了。修改:重新设置。修改:将其中一个符号 DATA 重 新设置。 3、test.asm(7): error A2009: Symbol not defined: B9H 、 说明:行指令出错,查看该指令,说明:此错误信息为 test.asm 中第 7 行指令出错,查看该指令,源操作数为十六进制 数 B9H。按规定以字母开始的十六进制数,应在其。按规定以 字母开始的十六进制数,以便汇编程序区分常数和符号。前面 加上数字 0 以便汇编程序区分常数和符号。另一种出错的可能 原因是程序中使用的符号变量没有定义。能原因是程序中使用 的符号变量没有定义。修改:修改:以 0B9H 取代 B9H;使用 伪指令定义变量。;使用伪指令定义变量。 4、test.asm(11): error A2009: Symbol not defined: NO 、 说明:说明:test.asm 中第 11 行指令 JLE no-count,符号中使 用了中折线,中,符号中使用了中折线,折线在汇编中是作为 减号,因此,没有定义。折线在汇编中是作为减号,因此,汇 编提示标号 NO 没有定义。注意,汇编语言规定符号中可以使 用下划线。注意,汇编语言规定符号中可以使用下划线。修改:修改:将 no-count 改为 no_count。。 5、test.asm(28): error A2010: Syntax error 、

汇编语言例子

实验三: 1)题目:在内存中从ARRAY开始的连续三个字节单元存放着30H,40H,50H。编制程序将这三个连续的数据传送到内存TABLE开始的单元。 DATA SEGMENT ARRAY DB 30H,40H,50H 定义数据段 TABLE DB 3 DUP (?) DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA START: MOV AX,DATA MOV DS,AX MOV ES,AX LEA SI,ARRAY LEA DI,TABLE MOV CX,3 REP MOVSB JMP $ CODE ENDS END START (2)题目:把内存2000H和3000H字单元的内容相加,结果存入4000H单元。(不考虑溢出) DATA SEGMENT ORG 2000H DW 1234H ORG 3000H DW 5678H ORG 4000H DW ? DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA START: MOV AX,DATA MOV DS,AX MOV AX,[2000H] ADD AX,[3000H] MOV [4000H],AX JMP $ CODE ENDS END START 实验四 1、数据传送指令和算术运算指令完成NUM1和NUM2相加,结果放入SUM中。

DATA SEGMENT NUM1 DW 0012H,0030H,0FC21H ; 数1 NUM2 DW 3E81H,44E9H,6D70H ; 数2 SUM D W 3 DUP(?) ; 结果单元 DATA ENDS CODE SEGMENT ASSUME CS: CODE, DS: DATA START: MOV AX, DATA MOV DS, AX MOV CX,3 LEA SI,NUM1 LEA DI,NUM2 LEA AX,SUM HE: MOV BX,[SI] ADD BX,[DI] MOV [AX],BX INC SI INC DI INC AX LOOP HE MOV AH, 4CH ; 返回DOS INT 21H CODE ENDS END START 2、内存中自TABLE开始的七个单元连续存放着自然数0至6的立方值(称作立方表)。;任给一数X(0≤X≤6)在XX单元,查表求X的立方值,并把结果存入YY单元中。;提示用XLAT指令 DATA SEGMENT TABLE DB 0H,1H,2H,3H,4H,5H,6H XX DB 1 DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA START: MOV AX,DATA MOV DS,AX LEA BX,TABLE MOV AL,[XX] XLAT MOV DL,AL MOV AH,02H INT 21H JMP $

C++中函数调用时的三种参数传递方式

在C++中,参数传递的方式是“实虚结合”。 ?按值传递(pass by value) ?地址传递(pass by pointer) ?引用传递(pass by reference) 按值传递的过程为:首先计算出实参表达式的值,接着给对应的形参变量分配一个存储空间,该空间的大小等于该形参类型的,然后把以求出的实参表达式的值一一存入到形参变量分配的存储空间中,成为形参变量的初值,供被调用函数执行时使用。这种传递是把实参表达式的值传送给对应的形参变量,故称这种传递方式为“按值传递”。 使用这种方式,调用函数本省不对实参进行操作,也就是说,即使形参的值在函数中发生了变化,实参的值也完全不会受到影响,仍为调用前的值。 [cpp]view plaincopy 1./* 2. pass By value 3.*/ 4.#include https://www.360docs.net/doc/8712754322.html,ing namespace std; 6.void swap(int,int); 7.int main() 8.{ 9.int a = 3, b = 4; 10. cout << "a = " << a << ", b = " 11. << b << endl; 12. swap(a,b); 13. cout << "a = " << a << ", b = " 14. << b << endl; 15.return 0; 16.} 17.void swap(int x, int y) 18.{ 19.int t = x; 20. x = y; 21. y = t; 22.}

如果在函数定义时将形参说明成指针,对这样的函数进行调用时就需要指定地址值形式的实参。这时的参数传递方式就是地址传递方式。 地址传递与按值传递的不同在于,它把实参的存储地址传送给对应的形参,从而使得形参指针和实参指针指向同一个地址。因此,被调用函数中对形参指针所指向的地址中内容的任何改变都会影响到实参。 [cpp]view plaincopy 1.#include https://www.360docs.net/doc/8712754322.html,ing namespace std; 3.void swap(int*,int*); 4.int main() 5.{ 6.int a = 3, b = 4; 7. cout << "a = " << a << ", b = " 8. << b << endl; 9. swap(&a,&b); 10. cout << "a = " << a << ", b = " 11. << b << endl; 12. system("pause"); 13.return 0; 14.} 15.void swap(int *x,int *y) 16.{ 17.int t = *x; 18. *x = *y; 19. *y = t; 20.} 按值传递方式容易理解,但形参值的改变不能对实参产生影响。 地址传递方式虽然可以使得形参的改变对相应的实参有效,但如果在函数中反复利用指针进行间接访问,会使程序容易产生错误且难以阅读。

MASM汇编错误信息说明 ASM问题汇总

MASM汇编错误信息说明 test.asm(54):error A2000:Block nesting error 1.1.test.asm(54): 说明:此错误信息通常见于一个段定义起始段名和末尾段名不一致。 修改:检查段定义,使段名前后保持一致。 test.asm(5):error A2005:Symbol is multidefined:DATA 2.2.test.asm(5): 说明:此错误信息提示DATA符号重复定义了。 修改:将其中一个符号DATA重新设置。 test.asm(7):error A2009:Symbol not defined:B9H 3.3.test.asm(7): 说明:此错误信息为test.asm中第7行指令出错,查看该指令,源操作数为十六进制数B9H。按规定以字母开始的十六进制数,应在其前面加上数字0以便汇编程序区分常数和符号。另一种出错的可能原因是程序中使用的符号变量没有定义。 修改:以0B9H取代B9H;使用伪指令定义变量。 test.asm(11):error A2009:Symbol not defined:NO 4.4.test.asm(11): 说明:test.asm中第11行指令JLE no-count,符号中使用了中折线,中折线在汇编中是作减号,因此,汇编提示标号NO没有定义。注意,汇编语言规定符号中可以使用下划线。 修改:将no-count改为no_count。 test.asm(28):error A2010:Syntax error 5.5.test.asm(28): 说明:此错误信息提示源程序中第28行的指令语句的语法与任何可识别的语法不匹配,出错。 修改:按照汇编指令的规定格式重新编写。 6.6.test.asm(2): test.asm(2):error A2018:Operand must be register:DX 说明:指定的寄存器不是指令或伪指令所要求的。如:ASSUME DX:DATA 修改:查看汇编指令的规定格式。

函数调用参数传递类型(java)的用法介绍.

函数调用参数传递类型(java)的用法介绍. java方法中传值和传引用的问题是个基本问题,但是也有很多人一时弄不清。 (一)基本数据类型:传值,方法不会改变实参的值。 public class TestFun { public static void testInt(int i){ i=5; } public static void main(String[] args) { int a=0 ; TestFun.testInt(a); System.out.println("a="+a); } } 程序执行结果:a=0 。 (二)对象类型参数:传引用,方法体内改变形参引用,不会改变实参的引用,但有可能改变实参对象的属性值。 举两个例子: (1)方法体内改变形参引用,但不会改变实参引用,实参值不变。 public class TestFun2 { public static void testStr(String str){ str="hello";//型参指向字符串“hello” } public static void main(String[] args) { String s="1" ;

TestFun2.testStr(s); System.out.println("s="+s); //实参s引用没变,值也不变 } } 执行结果打印:s=1 (2)方法体内,通过引用改变了实际参数对象的内容,注意是“内容”,引用还是不变的。 import java.util.HashMap; import java.util.Map; public class TestFun3 { public static void testMap(Map map){ map.put("key2","value2");//通过引用,改变了实参的内容 } public static void main(String[] args) { Map map = new HashMap(); map.put("key1", "value1"); new TestFun3().testMap(map); System.out.println("map size:"+map.size()); //map内容变化了 } } 执行结果,打印:map size:2 。可见在方法testMap()内改变了实参的内容。 (3)第二个例子是拿map举例的,还有经常涉及的是 StringBuffer : public class TestFun4 {

汇编语言编程规范

软件设计更多地是一种工程,而不是一种个人艺术。如果不统一编程规范,最终写出的程序,其可读性将较差,这不仅给代码的理解带来障碍,增加维护阶段的工作量,同时不规范的代码隐含错误的可能性也比较大。 分析表明,编码阶段产生的错误当中,语法错误大概占20%左右,而由于未严格检查软件逻辑导致的错误、函数(模块)之间接口错误及由于代码可理解度低导致优化维护阶段对代码的错误修改引起的错误则占了一半以上。 可见,提高软件质量必须降低编码阶段的错误率。如何有效降低编码阶段的错误呢?这需要制定详细的软件编程规范,并培训每一位程序员,最终的结果可以把编码阶段的错误降至10%左右,同时也降低了程序的测试费用,效果相当显著。 本文从代码的可维护性(可读性、可理解性、可修改性)、代码逻辑与效率、函数(模块)接口、可测试性四个方面阐述了软件编程规范,规范分成规则和建议两种,其中规则部分为强制执行项目,而建议部分则不作强制,可根据习惯取舍。 1.排版 规则1 程序块使用缩进方式,函数和标号使用空格缩进,程序段混合使用TAB和空格缩进。缩进的目的是使程序结构清晰,便于阅读和理解。 默认宽度应为8个空格,由于Word中为4个空格,为示范清晰,此处用2个代替(下同)。 例如: MOV R1, #00H MOV R2, #00H MOV PMR, #PMRNORMAL MOV DPS, #FLAGDPTR MOV DPTR, #ADDREEPROM read1kloop: read1kpage: INC R1

MOVX A, @DPTR MOV SBUF, A JNB TI, $ CLR TI INC DPTR CJNE R1, #20H, read1kpage INC R2 MOV R1, #00H CPL WDI CJNE R2, #20H, read1kloop ;END OF EEPROM 规则2 在指令的操作数之间的,使用空格进行间隔,采用这种松散方式编写代码的目的是使代码更加清晰。 例如: CJNE R2, #20H, read1kloop ;END OF EEPROM 规则3 一行最多写一条语句。 规则4 变量定义时,保持对齐。便于阅读和检查内存的使用情况。 例如: RegLEDLOSS EQU 30H ; VARIABLE ; TESTLED==RegLEDLOSS.0 RegLEDRA EQU 31H ; VARIABLE

单片机汇编语言常见错误分析

单片机汇编语言常见错误分析 一、汇编软件汇编失败原因分析: 这里采用Keil C51 软件包中的宏汇编器A51 作为编绎器,单片机的汇编语言编写时要注意一定的语法,详细介绍可以参考相关参考书,语法错误会造成 汇编失败,常见的汇编错误如下:1. 标号重复:常见于复制、粘贴程序时忘 记修改标号,造成出现多个相同的标号,标号是不允许重复的。2.标点符号 以全角方式输入:汇编程序要求标点符号为半角方式,否则汇编失败。可以 在输入:,;时切换到半角方式,或者在大写状态输入标点符号,这也是很容易 犯而且不容易发觉的错误。3.数值#FFH 前遗漏0:根据要求应该在a~f 前加0,写成#0FFH4.字母O 和数字0 搞混:有时候这两个字看上去完全相同,要注意哦~~5.标号后边遗漏”:”6.标号使用了特殊字符:标号不能用指令 助记符、伪指令、特殊功能寄存器名和8051 在指令系统中用的“#”、“@”等,长 度以2~6 字符为宜,第一字母必须是英文字母。比如:T1、T2、A、B 这些字 符有特定的含义,不允许用于标号。7.AJMP 跳转超过2K 地址:AJMP 属于短跳转命令,有2K 地址范围的限制。8.超过地址范围:JB P3.2,EXIT 跳转超过-128~127 个地址范围。这个是最容易出现的错误!你有可能程序刚才还 能汇编编译成功,你加了一段程序后程序就提示出错了,你可以把JB P3.2,EXIT 转换成JNB P3.2,LD01AJMP EXITLD01: AJMP EXIT……9.字母I 和数字1 混淆:冒失鬼的常见问题。10.创造发明不存在的汇编语言指令:在编写程序程序的过程中可不欢迎这种创新,这种指令汇编程序不支持,芯片也不 认可。11.符号“:”“;”最好用半角书写。 二、程序出错: 1.寄存器重复调用:比如主程序中设定了R4=5,表示主程序循环执行5 次,

arm汇编语言调用C函数之参数传递

arm汇编语言调用C函数之参数传递 于ARM体系来说,不同语言撰写的函数之间相互调用(mix calls)遵循的是 ATPCS(ARM-Thumb Procedure Call Standard),ATPCS 主要是定义了函数呼叫时参数的传递规则以及如何从函数返回,关于ATPCS的详细内容可以查看ADS1.2 Online Books ——Developer Guide的2.1节。这篇文档要讲的是汇编代码中对C函数调用时如何进行参数的传递以及如何从C函数正确返回。 不同于x86的参数传递规则,ATPCS建议函数的形参不超过4个,如果形参个数少于或等于4,则形参由R0,R1,R2,R3四个寄存器进行传递;若形参个数大于4,大于4的部分必须通过堆栈进行传递。 我们先讨论一下形参个数为4的情况. 实例1: test_asm_args.asm //-------------------------------------------------------------------------------- IMPORT test_c_args ;声明test_c_args函数 AREA TEST_ASM, CODE, READONLY EXPORT test_asm_args test_asm_args STR lr, [sp, #-4]! ;保存当前lr ldr r0,=0x10 ;参数 1 ldr r1,=0x20 ;参数 2

ldr r2,=0x30 ;参数 3 ldr r3,=0x40 ;参数 4 bl test_c_args ;调用C函数 LDR pc, [sp], #4 ;将lr装进pc(返回main函数) END test_c_args.c //-------------------------------------------------------------------------------- void test_c_args(int a,int b,int c,int d) { printk("test_c_args:\n"); printk("%0x %0x %0x %0x\n",a,b,c,d); } main.c //-------------------------------------------------------------------------------- int main() { test_asm_args(); for(;;); } 程序从main函数开始执行,main调用了test_asm_args,test_asm_args 调用了test_c_args,最后从test_asm_args返回main。代码分别使用了

单片机编程时常见的十大问题解答

单片机编程时常见的十大问题解答 1.C 语言和汇编语言在单片机编程时各有哪些优缺点?答:汇编语言是一种用文字助记符来表示机器指令的符号语言,是最接近机器码的一种语言。其主要优点是占用资源少、程序执行效率高。但是不同的CPU,其汇编语言可能有所差异,所以不易移植。 C 语言是一种结构化的高级语言。其优点是可读性好,移植容易,是普遍使用的一种计算机语言。缺点是占用资源较多,执行效率没有汇编高。 对于目前普遍使用的RISC 架构的8bit MCU 来说,其内部ROM、RAM、STACK 等资源都有限,如果使用C 语言编写,一条C 语言指令编译后,会变成很多条机器码,很容易出现ROM 空间不够、堆栈溢出等问题。而且一些单片机厂家也不一定能提供C 编译器。而汇编语言,一条指令就对应一个机器码,每一步执行什幺动作都很清楚,并且程序大小和堆栈调用情况都容易控制,调试起来也比较方便。所以在单片机开发中,我们还是建议采用汇编语言比较好。 2.C 或汇编语言可以用于单片机,C++能吗?答:在单片机编程中,主要是汇编和C,没有用C++的。 3.搞单片机编程,一定要会C 吗?答:汇编语言是一种用文字助记符来表示机器指令的符号语言,是最接近机器码的一种语言。其主要优点是占用资源少、程序执行效率高。但是不同的CPU,其汇编语言可能有所差异,所以不易移植。 对于目前普遍使用的RISC 架构的8bit MCU 来说,其内部ROM、RAM、STACK 等资源都有限,如果使用C 语言编写,一条C 语言指令编译后,会变成很多条机器码,很容易出现ROM 空间不够、堆栈溢出等问题。而且一些单片机厂家也不一定能提供C 编译器。而汇编语言,一条指令就对应一个机器码,每一步执行什么动作都很清楚,并且程序大小和堆栈调用情况都容易控制,调试起来也比较方便。所以在资源较少单片机开发中,我们还是建议采用汇编语言比较好。 而C 语言是一种编译型程序设计语言,它兼顾了多种高级语言的特点,并具备汇编语言

汇编伪指令和编译出错说明

ASM-51 宏汇编使用手册 A51与ASM51基本相同 ASM-51 宏汇编主要用来开发Inter8051系列单片机,它具有宏处理,数据处理,列表处理和条件处理等多种功能。源程序的编写完全采用 Inter标准助记符和行格式。在编写程序过程中,可借助于文本编辑(Windows的记事本)或文字处理软件Word等编辑,经ASM-51汇编后生成列表输出文件(.LST)和目标代码文件(.HEX)。此目标代码文件(.HEX)可直接用CZS-51或MedWin、Keil、Debug8051进行模拟/调试,或直接用于硬件仿真器上运行。当然,这也是要烧写到单片机ROM中的代码。 1、宏汇编语言的基本语法 1、1 宏汇编的特点 ASM-51宏汇编完全支持Inter助记符的汇编语言,它含有宏语句,英文大小写字母,变量名,标号等不受限制,有二,十,十六进制和串参数类型,有汇编控制指令和多层条件语句,程序逻辑分段,还有模块化程序设计的连接功能,汇编速度快等特点。 1、2 汇编处理过程 (1) 用行编辑EDLIN或文字处理软件WS或全屏幕编辑软件PE等,编辑宏汇编 语言源程序,它的文件扩展名为。ASM。 (2) 用ASM-51宏汇编程序对上述源程序文件进行汇编,产生扩展名为.LST的列表输出文件和扩展名为.HEX的目标代码文件(.HEX)。列表输出文件包含源程序语句所汇编成的代码,以及有关的地址,语句和符号表等。目标代码文件包含源程序语句所汇编成的代码,不包含任何符号信息或助记符。进行模拟/调试,或直接用于硬件仿真器上运行。 1、3 语句 汇编语言可分为两类语句:指令性语句和指示性语句。 (1)指令性语句 这一类语句是指在汇编过程中能生成指令代码的语句(如 MOV ,DEC等)。其格式为: [标号:] [指令助记符] [操作数] [;注释] 其中方括号[ ]中为选择项。下同。 (2)指示性语句

相关文档
最新文档