1 / 45

微机原理与接口技术 第三章: 汇编语言程序设计

微机原理与接口技术 第三章: 汇编语言程序设计. 主讲人:鞠 雷 山东大学 计算机科学与技术学院.  内容提要. 汇编语言源程序格式. 文件类型. 扩展名. 汇编语言文件. . s. C 语言源文件. . c. C++ 源文件. . cpp. 引入文件. . INC. 头文件. . h. ARM 源程序文件. .h 文件给出函数和变量的声明 . .c 文件给出函数的定义. 使用简单的文本 编辑器或者其他 的编程开发环境 进行编辑. 引入其他程序中的变量或函数 , 在本程序使用. Arm 源程序汇编连接过程:.

Download Presentation

微机原理与接口技术 第三章: 汇编语言程序设计

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 微机原理与接口技术第三章:汇编语言程序设计微机原理与接口技术第三章:汇编语言程序设计 主讲人:鞠 雷 山东大学 计算机科学与技术学院

  2.  内容提要 汇编语言源程序格式

  3. 文件类型 扩展名 汇编语言文件 .s C语言源文件 .c C++源文件 .cpp 引入文件 .INC 头文件 .h ARM源程序文件 .h文件给出函数和变量的声明. .c文件给出函数的定义. 使用简单的文本 编辑器或者其他 的编程开发环境 进行编辑. 引入其他程序中的变量或函数,在本程序使用.

  4. Arm源程序汇编连接过程: 例 armasmhello.s armlinkhello.o -o hello.axf armsd -exec hello.axf; armcc -g hello.s -o hello.axf

  5. 2 1 3 汇编语言程序的结构 汇编语言的行构成 伪指令 汇编语言源程序格式

  6. 1.汇编语言程序的结构 在ARM(Thumb)汇编语言程序中,以程序段为单位组织代码。 用AREA伪指令定义一个段,并说明所定义段的相关属性. 段是相对独立的指令或数据序列,具有特定的名称。 段分为代码段和数据段,代码段的内容为执行代码,数据段存放代码运行时需要用到的数据。  一个汇编程序至少应该有一个代码段,当程序较长时,可以分割为多个代码段和数据段,多个段在程序编译链接时最终形成一个可执行的映象文件。 汇编源程序示例第一部分(test0源程序) ARM的汇编语言程序 一般由几个段组成, 每个段均由AREA伪操 作定义。 CODE32 ;32位的ARM指令段 AREA codesec, CODE, READONLY ;代码段,名称codesec,属性为 ;只读 main PROC ;函数main STMFD sp!,{lr} ;保存返回地址到数据栈 ADR r0,strhello ;取标签strhello的地址 BL _printf ;调用C运行时库的_printf函数 ;打印“Hello world!”字符串 BL welcomefun ;调用子函数welcomfun LDMFD sp!,{pc} ;返回调用函数 strhello ;strhello代表本地字符串的地址 DCB "Hello world!\n\0" ;定义一段字节空间 ENDP ;函数main结束 段可以分为多种,如代码段、 数据段、通用段,每个段又有 不同的属性,代码段的默认 属性为READONLY,数据段的默 认属性为READWRITE。 • 本程序定义了两个段, • 第一个段为代码段codesec; 多个代码段的情况,一个源文件只能含一个代码段并单独编译,多个代码段分别编译最后连接成映象文件。 可执行映象文件的构成: 一个或多个代码段,代码段的属性为只读。 零个或多个包含初始化数据的数据段,数据段的属性为可读写。 零个或多个不包含初始化数据的数据段,数据段的属性为可读写。

  7. 1.汇编语言程序的结构 汇编源程序示例第二部分 welcomefun ;子函数welcomfun STMFD sp!,{lr} ;保存返回地址到数据栈 ADR r0,adrstrarm ;取adrstrarm的地址放到寄存器r0中 LDR r0,[r0,#0] ;将strarm的值放到r0中 BL _printf ;调用C运行时库的_printf函数打印 ; “Welcom to ARM world!”字符串 LDMFD sp!,{pc} ;返回调用函数 adrstrarm ;adrstrarm标签 DCD strarm ;保存strarm的地址 AREA constdatasec, DATA, READONLY,ALIGN=0 ; • 本程序定义了两个段, • 第二个段为数据段constdatasec

  8. 1.汇编语言程序的结构 导出main函数供其他程序使用. 汇编源程序示例第三部分 导入main PROC ENDP,在本程序使用. strarm DCB "Welcome to ARM world!\n\0" ;存放“Welcome to ARM ; world!”字符串 EXPORT main ;导出main函数供外部调用 ;引入三个C运行时库函数和ARM库 IMPORT _main IMPORT __main IMPORT _printf IMPORT ||Lib$$Request$$armlib||, WEAK END ;源程序结束 导入ARM库。WEAK,若导入符号不存在不给出错误信息.

  9. 2.汇编语言的行构成 • 格式: [标签] 指令/伪操作 操作数 [;语句的注释] • 所有的标签必须在一行的开头顶格写,前面不能留空格,后面不加“:”; • ARM汇编器对标识符的大小写敏感,书写标号及指令时字母的大小写要一致; • 注释使用“;”符号,注释的内容从“;”开始到该行的结尾结束。 • 例: • Labeladd add r0,r0,r1 ;加法指令 • Str1 SETS “This is a string.” ;给字符串Str1赋值

  10. 2.汇编语言的行构成 1.标签: • 标签是一个符号,可以代表指令的地址、变量、数据的地址和常数。 • 一般以字母开头,由字母、数字、下划线组成。 • 标签不能采用关键字。 • 标签(标号)代表可执行语句地址。 • 标号按其作用域可分为段内标号和和段外标号: • 段内标号的地址值在汇编时确定。 • 例 welcomefun • 段外标号的地址值在链接时确定。 • 例 EXPORT main • 段外调用:BL main • 局部标号,宏中使用的标号称之为局部标号。

  11. 2.汇编语言的行构成 2.指令/伪操作: 指令/伪操作的助记符或者定义符,通知ARM的处理器应该执行什么样的操作或者通知汇编程序伪操作的功能。 3.操作数 由寄存器名、变量名和常量组成的表达式。 例 addr0,r1, r2 x dcd 0x12

  12. 2.汇编语言的行构成 伪操作使用的常量: • 数字常量(伪操作不加#) • 十进制数,如1、2、123 • 十六进制数,如 0x123,0xabc • 2_1010 • 字符常量 • 由单引号及中间的字符组成,包括C语言中的转义字符,如‘\a’,‘\n’ ( 响铃,换行) • 字符串常量 • 由一对双引号及中间的字符串表示,中间也可以使用C语言中的转义字符,比如:“abcdef\a\r\n” • 逻辑常量 • {TRUE},{FALSE},注意带大括号

  13. 3.伪操作 • 没有相对应的操作码或者机器码,通常称为伪指令。 • 作用是为完成汇编程序作各种准备工作的,由汇编程序在源程序的汇编期间进行处理,仅在汇编过程中起作用 (取地址伪指令与其他伪指令有较大区别) 。 • 有如下几种伪操作: • 符号定义伪操作 定义一个内存变量。 • 数据定义伪操作 分配连续内存并初始化。定义多个连续内存变量。 • 汇编控制伪操作 控制汇编过程。

  14. 3. 伪操作 • 符号定义伪操作(定义一个内存变量) • 用于定义ARM汇编程序中的变量、对变量赋值等。 • 符号定义有如下几种伪操作: • 用于定义局部变量的LCLA、LCLL、LCLS (在宏中使用,不讲) • 用于定义全局变量的GBLA、GBLL、GBLS ; • 用于对变量赋值的SETA、SETL、SETS; 局部变量在宏中定义使用!

  15. 3.伪操作 GBLA、GBLL、GBLS 伪操作 定义一个汇编程序中的全局变量。 格式:GBLA/ GBLL/ GBLS变量名 定义一个全局的数字变量,并初始化为0 定义一个全局的逻辑变量,并初始化为F 定义一个全局字符串变量,并初始化为空串 • 全局变量在整个程序范围内变量名必须唯一。

  16. 3.伪操作 例: • GBLA num1 ;定义一个全局的数字变量num1,初值0 • num1 SETA 0xabcd • GBLL l2 ;定义一个全局的逻辑变量,变 ;量名为l2,初值为F • l2 SETL {FALSE} ;将该变量赋值为假 • GBLS str3 ;定义一个全局的字符串变量str3,初值空串。 • str3 SETS “Hello!”

  17. 3.伪操作 • SETA、SETL、SETS 格式:变量名 SETA/SETL/SETS表达式 给一个数字变量赋值 给一个逻辑变量赋值 给一个字符串变量赋值 • 格式中的变量名必须为已经定义过的全局或局部变量,表达式为将要赋给变量的值。

  18. 3.伪操作 例: • GBLA num1 ;定义全局数字变量 • num1 SETA 0x1234 ;赋值为0x1234 • GBLS str3 ;定义全局字符串变量 • str3 SETS “Hello!” ;赋值为“Hello!”

  19. 3.伪操作 • 数据定义伪操作 • 分配存储单元,并初始化。 • 数据定义有如下几种伪指令: • DCB 分配字节 • DCW/DCWU 分配半字 • DCD/DCDU 分配字 • SPACE • MAP • FIELD 定义多个连续内存变量. 定义连续内存空间. 定义内存表.

  20. 3.伪操作 • DCB DCB用于分配一块字节单元并用伪指令中指定的表达式进行初始化。 格式:标号/变量 DCB表达式 表达式可以为使用双引号的字符串或0-255的数字 DCB可用“=”代替 例: Array1 DCB 1,2,3,4,5 ;数组 str1 DCB “Your are welcome!” ;构造字符串 ;并分配空间

  21. 3.伪操作 • DCW/DCWU 格式:标号/变量 DCW/DCWU表达式 DCW分配若干个半字存储单元并用表达式值初始化,存储空间半字对齐。 DCWU功能跟DCW类似,只是分配的字存储单元不严格半字对齐 • 例: • Arrayw1 DCW 0xa,-0xb,0xc,-0xd ;构造固定数组并分 • ; 配半字存储单元

  22. 3.伪操作 • DCD/DCDU 格式:标号/变量 DCD/DCDU表达式 分配若干个字存储单元并用表达式初始化,存储空间字对齐。也可用“&”代替 DCDU只是分配的存储单元不严格字对齐 例: Arrayd1 DCD 1334,234,345435 ;构造固定数组并分配 ;字为单元的存储单元Label DCD str1 ;该字单元存放str1的地址

  23. 3.伪操作 • SPACE 格式: 标号 SPACE表达式 SPACE用于分配一片连续的存储区域并初始化为0,也可用“%”代替 表达式为要分配的字节数 • 例: • Freespace SPACE 1000 ;分配1000字节的存储空间

  24. 3.伪操作 • MAP 格式:MAP 表达式 [,基址寄存器] MAP定义一个结构化的内存表的首地址。 表达式可以为程序中的标号或数学表达式 内存表首地址= (基址寄存器)+表达式 • MAP可以与FIELD伪操作配合使用来定义结构化的内存表。 • 例: • MAP 0x130,R2 ;内存表首地址为0x130+R2

  25. 3.伪操作 • FILED 格式:标号 FIELD字节数 定义一个结构化内存表中数据域的的字节数。 可用“#”来代替FILED • FIELD常与MAP配合使用: • MAP 定义内存表的首地址 • FIELD 定义内存表中的各个数据域的字节数并分配存储单元。

  26. 3.伪操作 例: MAP 0xF10000 ;定义结构化内存表首地址为 ;0xF10000 count FIELD 4 ;定义count的长度为4字节, ;位置为0xF10000 x FIELD 4 ;定义x的长度为4字节,位置 ;为0xF10004 y FIELD 4 ;定义y的长度为4字节,位置 ;为0xF10008

  27. 其他伪操作 • AREA 格式: AREA段名 属性,…… AREA用于定义一个代码段、数据段或者特定属性的段 属性部分表示该代码段/数据段的相关属性,多个属性可以用“,”分隔。 • 常见属性如下: • DATA:定义数据段。 • CODE:定义代码段。 • READONLY:表示本段为只读。 • READWRITE:表示本段可读写。

  28. 其他伪操作 • 一个汇编程序至少应该包含一个代码段,当程序太长时,也可以将程序分为多个代码段和数据段。 • 例: • AREA test,CODE,READONLY • AREA ||.text||, CODE, READONLY 出现非法字符”.”, 以”||”使其合法化.

  29. 其他伪操作 • CODE16、CODE32 格式: CODE16/CODE32 CODE16伪操作指示编译器后面的代码为16位的Thumb指令 CODE32伪操作指示编译器后面的代码为32位的ARM指令 • 在汇编源代码中同时包含Thumb和ARM指令时,须用 “CODE32”和“CODE16”伪指令通知编译器其后的指令序列的类型。 • “CODE32”和“CODE16”不能对处理器进行状态的切换。

  30. 其他伪操作 • ENTRY 格式: ENTRY ENTRY用于指定汇编程序的入口。在一个完整的汇编程序中至少要有一个ENTRY,也可以有多个。 • 下面的代码使用了ENTRY: • AREA subrout, CODE, READONLY • ENTRY ;指定程序入口 • start • MOV r0, #10 ;设置参数 • MOV r1, #3 • BL doadd ;调用子函数

  31. 其他伪操作 stop MOV r0, #0x18 ;设置软中断输入参数 LDR r1, =0x20026 SWI 0x123456 ;调用ARM 软中断返回 ;cpu控制权交给调试器 doadd ADD r0, r0, r1 ;子函数代码 MOV pc, lr ;子函数返回 END ; 源文件结束

  32. 其他伪操作 • END 格式:END END告诉编译器已经到了源程序的结尾 • 例: • AREA constdata,DATA,READONLY • …… • END ;结尾

  33. 其他伪操作 • EQU 格式:名称 EQU表达式[,类型] 若表达式为32位的常量或32位地址常量,可以指定表达式的数据类型。有以下三种类型: DATA 表明该地址处为数据区 CODE16 表明该地址处为thumb指令 CODE32 表明该地址处为arm指令 将程序中的数字常量、标号赋予一个等效的名称。 • 例: • num1 EQU 1234 ;定义num1为1234 • addr5 EQU str1+0x50 • d1 EQU 0x2400,CODE32 • ;定义d1的值为0x2400,且 • ;该处为32位的ARM指令

  34. 其他伪操作 • EXPORT 格式: EXPORT标号[,WEAK] EXPORT 在程序中声明一个全局标号,其他文件中的代码可以引用该标号。用户也可以用GLOBAL代替EXPORT [,WEAK]可选项若其他文件有同名的标号,则其他文件同名标号优先被引用。 • 例: • AREA ||.text||,CODE,READONLY • main PROC • …… • ENDP • EXPORT main ;声明一个可全局引用的函数main • END

  35. 其他伪操作 • IMPORT 格式: IMPORT标号 [,WEAK] 通知编译器此标号在当前源文件中使用,但标号是在其他的源文件中定义的。 不管当前源文件是否使用过该标号,这个标号都被加入到当前源文件的符号表中 [,WEAK]选项表示如果所有的源文件都没有找到这个标号的定义,编译器也不会提示错误信息。 出错时该标号置为0。如果这个标号被B或BL指令引用,则将B或BL指令替换为NOP操作。 • 例: • AREA mycode,CODE,READONLY • IMPORT _printf ;通知编译器当前文件要引用函 ;数_printf • END

  36. 其他伪操作 • EXTERN 格式: EXTERN标号 [,WEAK] [,WEAK]选项表示如果所有的源文件都没有找到这个标号的定义,编译器也不会提示错误信息。 出错时该标号置为0。如果这个标号被B或BL指令引用,则将B或BL指令替换为NOP操作。 通知编译器此标号在当前源文件中使用,但标号是在其他的源文件中定义的。 与IMPORT不同的是,如果该标号未被引用,则该标号不被加入到当前文件的符号表中。 • 例: • AREA ||.text||,CODE,READONLY • EXTERN _printf ,WEAK ;告诉编译器当前文件要引用标 • ;号,如果找不到,则不提示错误 • END

  37. 其他伪操作 • INCBIN 格式: INCBIN文件名 INCBIN将一个数据文件或者目标文件包含到当前的源文件中,编译时被包含的文件不作任何变动的存放在当前文件中,编译器从后面开始继续处理。 • 例: • AREA constdata,DATA,READONLY • INCBIN data1.dat ;源文件包含文件data1.dat • INCBIN E:\DATA\data2.bin ;源文件包含文件 • ;E:\DATA\data2.bin • END

  38. ARM Procedure Call Standard (APCS) • ARM过程调用规范 • 一套函数调用者与被调用之间的协议 • 对寄存器使用的限制。 • 使用栈的惯例。 • 在函数调用之间传递/返回参数。 • 可以被‘回溯’的基于栈的结构的格式,用来提供从失败点到程序入口的函数(和给予的参数)的列表。 • APCS 不一个单一的给定标准,而是一系列类似但在特定条件下有所区别的标准 • 牺牲部分的系统性能,提升程序的通用性

  39. APCS • 子程序间通过寄存器R0-R3来传递参数,这时,寄存器R0-R3可以记作A1-A4。被调用的子程序在返回前无需恢复寄存器R0-R3的内容。 • 在子程序中,使用寄存器R4-R11来保存局部变量.这时,寄存器R4-R11可以记作V1-V8。如果在子程序中使用到了寄存器V1-V8中的某些寄存器,子程序进入时必须保存这些寄存器的值,在返回前必须恢复这些寄存器的值;对于子程序中没有用到的寄存器则不必进行这些操作。在Thumb程序中,通常只能使用寄存器R4-R7来保存局部变量。 • 寄存器R12用作子程序间scratch寄存器(用于保存SP,在函数返回时使用该寄存器出栈),记作ip。在子程序间的连接代码段中常有这种使用规则。

  40. APCS • 寄存器R13用作数据栈指针,记作sp。在子程序中寄存器R13不能用作其他用途。寄存器sp在进入子程序时的值和退出子程序时的值必须相等。 • 寄存器R14称为连接寄存器,记作lr。它用于保存子程序的返回地址。如果在子程序中保存了返回地址,寄存器R14则可以用作其他用途。 • 寄存器R15是程序计数器,记作pc。它不能用作其他用途。

  41. 补充习题 1、利用全局变量和局部变量声明伪操作及其赋值伪操作,分别定义算术变量、逻辑变量和串变量并为其赋值。

  42. 2、读懂下面一段程序,子程序dststr执行过程中寄存器R0、R1、R2中的内容如何变化?试分析并给出子程序执行后的结果(dststr所存内容)。2、读懂下面一段程序,子程序dststr执行过程中寄存器R0、R1、R2中的内容如何变化?试分析并给出子程序执行后的结果(dststr所存内容)。 AREA StrCopy, CODE, READONLY ENTRY ; mark the first instruction to call start LDR r1, =srcstr ; pointer to first string LDR r0, =dststr ; pointer to second string BL strcopy ; call subroutine to do copy stop MOV r0, #0x18 LDR r1, =0x20026 SWI 0x123456

  43. strcopy LDRB r2, [r1],#1 STRB r2, [r0],#1 CMP r2, #0 BNE strcopy MOV pc,lr ; Return AREA Strings, DATA, READWRITE srcstr DCB "First string - source",0 dststr DCB "Second string - destination",0 END

  44. AREA max_min, CODE, READONLY ENTRY ldr r0,=BUFF LDR R1,[R0];R1=MAX 最大值 MOV R2,R1 ;R2=MIN 最小值 MOV R4,#0 ;counter BEGIN LDR R3,[R0] CMP R3,R1 BLT LESS MOV R1,R3 LESS CMP R3,R2 BGT GREAT MOV R2,R3

  45. GREAT ADD R0,R0,#4 ; ADD R4,R4,#1 CMP R4,#9 BNE BEGIN str r1,max str r2,min MOV r0, #0x18 LDR r1, =0x20026 SWI 0x123456 AREA data, DATA, READWRITE BUFF DCD 0,-1,2,-3,4,5,6,7,9 max dcd 0 min dcd 0 END

More Related