1.45k likes | 1.63k Views
第 4 章 汇编语言程序设计 . 本 章结合 C54x 的软件开发过程,介绍 DSP 所采用的 COFF 目标文件格式 、结构和规范。介绍汇编 语 言的 重要组成部分: 伪 指 令 Assembler directives 和 宏 指 令 Macro directives 。 讨论建立汇编语言程序并产生可执行文件的设计要求。指出汇编程序设计中的一些关键问题,并通过实例介绍设计的方法和技巧。. 参考: TMS320C54x Assembly Language Tools User’s Guide.pdf, SPRU102F , 2002 年, TI 官网.
E N D
第4章 汇编语言程序设计 本章结合C54x的软件开发过程,介绍DSP所采用的COFF目标文件格式、结构和规范。介绍汇编语言的重要组成部分:伪指令Assembler directives和宏指令Macro directives。讨论建立汇编语言程序并产生可执行文件的设计要求。指出汇编程序设计中的一些关键问题,并通过实例介绍设计的方法和技巧。 参考:TMS320C54x Assembly Language Tools User’s Guide.pdf, SPRU102F,2002年,TI官网 参考:TMS320C54x Code Composer Studio Tutorial.pdf,spru327c,2000,TI官网
第4章 汇编语言程序设计 目录: • 4.1 C54x的软件开发过程 • 4.2 公共目标文件格式COFF • 4.3 汇编器的伪指令 • 4.4 C54x汇编语言的有关知识 • 4.5 汇编语言程序设计
第4章 汇编语言程序设计 • 4.1 C54x的软件开发过程 提供2种编程语言:汇编语言 C/C++语言 对于完成一般功能的代码,这两种语言都可使用,但对于一些运算量很大的关键代码,最好采用汇编语言来完成,以提高程序的运算效率。 C54x的软件开发过程可以分为文本编辑、编译、汇编和连接这样四个基本步骤,如图4-1所示。
第4章 汇编语言程序设计 • C54x的软件开发需要借助于TI公司提供的软件开发工具:编译器、汇编器和连接器,另外还有一些辅助的软件包,如归档器、列表器和代码转换器等。 • 这些软件开发工具都被集成在CCS(Code Composer Studio)开发环境中。将在第6章详细介绍CCS的组成及其使用方法
汇编器和链接器生成的目标文件,是一个可以由C54x器件执行的文件。这些目标文件的格式称之为公共目标文件格式(COFF)。汇编器和链接器生成的目标文件,是一个可以由C54x器件执行的文件。这些目标文件的格式称之为公共目标文件格式(COFF)。 4.2 公共目标文件格式COFF COFF:common object file format 采用这种文件格式的优点是: 将指令和数据按照段的概念进行组织和存储,这使得程序的可读性大大增强,更容易编写程序,更便于进行程序的移植,更利于进行模块化的程序设计,为管理代码段及系统存储器提供了灵活的方法和手段。
第4章 汇编语言程序设计 COFF文件有3种类型:COFF0、COFF1、COFF2 每种类型的COFF文件,其标题格式都有所不同,但数据部分是相同的。 链接器能够读/写所有类型的COFF文件,默认时链接器生成的是COFF2文件,采用-v n链接选项可以选择不同类型的COFF文件。
第4章 汇编语言程序设计 4.2.1分段结构 所谓“段”就是在存储器映像中占据连续空间的一段独立的代码或数据。每个目标文件都分成若干段。 • COFF目标文件包含以下三个默认的段: • .text 段:通常内含可执行代码; • .data段:通常内含已初始化数据; • .bss段:是为没有初始化的数据保留空间的。 COFF目标文件的段又可分为两大基本类型:已初始化段和未初始化段。
第4章 汇编语言程序设计 • Section( “段”)概念:一块连续的储存空间,可存放程序或数据 • 在编程时,“段”没有绝对定位,每个“段”都认为是从0地址开始的一块连续的储存空间,而无需关心这些“段”究竟定位在系统的哪些地方。 • 优点:便于程序的模块化编程;便于工程化管理:可将软件开发人员和硬件开发人员基本上分离开。 • 重定位:由于所有的“段”都是从0地址开始,所以程序编译完成后是无法运行的,要让程序正确运行,必须对“段”进行重新定位,这个工作由链接器完成。 • .cmd文件:MEMORY命令描述系统硬件资源,SECTIONS命令描述软件人员程序中用到的“段”如何定位到恰当的硬件资源上。
第4章 汇编语言程序设计 1.已初始化段 包含程序代码、常数表格和数据。每个段都可以独立的进行重定位,且可访问在其它段中定义的符号。已初始化段的值是不可修改的,因而一般将它们建立在程序存储器中。 主要有: .text段——已初始化段; .data段——已初始化段; .sect段——已初始化段,由汇编器伪指令建立的自定义段。
第4章 汇编语言程序设计 2.未初始化段 是为变量在数据存储器中保留空间的。它们在目标文件中没有实际内容,只是保留出空间,在运行程序时再利用这些空间去建立和存储变量。未初始化段一般应建立在片内或片外RAM中。 • 由这些段定义的空间仅作为临时存储空间,在程序运行时,可以利用这些存储空间存放变量。 • 未初始化段分为默认的和命名的两种,分别由汇编器伪指令.bss和.usect产生。.
目标文件 目标存储器 第4章 汇编语言程序设计 One of the linker’s functions is to relocate sections into the target memory map;this function is called allocation. 目标文件中的段与目标存储器之间的关系: .bss RAM .data E2PROM .text ROM
第4章 汇编语言程序设计 • 汇编器对段的处理是通过段伪指令来区别各个段的,并将段名相同的语句汇编在一起。 • 汇编器有5条伪指令可识别汇编语言程序的各个部分: 3. 段定义伪指令 ●.bss ● .usect ● .text ● .data ● .sect ——定义未初始化段 ——定义未初始化段 ——定义已初始化段 ——定义已初始化段 ——定义已初始化段
第4章 汇编语言程序设计 • 定义已初始化段的伪指令 .text [段起点] .data [段起点] .sect “段名”[,段起点] 段起点——是任选项。 若选用,它为段程序计数器SPC定义一个起始值。 若默认,则SPC从0开始。
定义未初始化段的伪指令 (1) .bss伪指令: 用于在bss段中保留若干个空间。 格式:.bss 符号, 字数 [, [块标记][, 定位对齐标记]] 符号—对应于保留的存储空间第一个字的变量名称。 字数—表示在bss段或标有名字的段中保留若干个存储单元。 块标记—若非零值,则分配的字数空间连续,除非大于一页,否则不跨页。 定位标记—表明字的对齐方式(C54x偶地址对齐) • 每调用一次.bss伪指令,汇编器在相应的段保留更多的空间。
第4章 汇编语言程序设计 • 定义未初始化段的伪指令 (2) .usect伪指令 用于为指定的命名段保留若干个空间。 格式: 标号 .usect “段名”,字数 [, [块标记][, 定位标记]] 建立一个自定义段但是没有初始化的段,在自定义的段中保留空间。 每调用一次.usect伪指令,汇编器在指定的命名段保留更多的空间。
第4章 汇编语言程序设计 • 例4-1:段定义程序举例。 .text .word 1,2,3,4,5,6,7,8 .data .word 9,10,11,12 .word 13,14 .word 15,16 .sect “var1” .word 17,18 .bss x1,19 ;为.bss段保留19个字单元空间。 y1.usect “var2”, 40; 为var2段保留40个单元空间。
例4-1:段定义程序举例。 程序建立了5个段,情况如下: .text .word 1,2,3,4,5,6,7,8 .data .word 9,10,11,12 .word 13,14 .word 15,16 .sect “var1” .word 17,18 .bssx1,19 ; y1.usect “var2”, 40; .text段:8个16位字1~8。 .data段:8个16位字9~16。 Var1段:2个16位字17,18。 .bss段:保留19个字的连续空间,第一个单 元的标号是x1。 Var2段:保留40个字的连续空间,第一个单元的标号是y1。
第4章 汇编语言程序设计 4.2.2 汇编器对段的建立 • 当汇编器遇到.text或.data或.sect命令时,将停止对当前段的汇编(相当于一条结束当前段汇编的命令),然后将紧接着的程序代码或数据汇编到指定的段中,直到再遇到另一条.text、.data或.sect命令为止。 • 当汇编器遇到.bss或.usect命令时,并不结束当前段的汇编,只是暂时从当前段脱离出来,并开始对新的段(.bss或.usect)进行汇编,结束后仍在离开时的段。(见例4-2)
第4章 汇编语言程序设计 4.2.2 汇编器对段的建立 段程序计数器SPC 汇编器为每个段都安排了一个单独的程序计数器称之为段程序计数器SPC。 SPC表示在程序代码或数据段内当前的地址。开始时汇编器将每个SPC置0。当汇编器将程序代码或数据加到段内时,增加相应的SPC值。若再继续对某个段汇编,则相应的SPC就在先前的数值上继续增加。
汇编语言源程序: ;初始化数据段 ;3组数据放入.data段 ;在.bss段保留10个单元;.bss后0123h仍然在.data段 ;初始化文本段 ;1字指令(DP直接寻址) ;2字指令 ;2字指令 .data coeff .word 011h,022h,033h .bss buffer,10 prt .word 0123h .text add: LD 0Fh,A Aloop: SUB #1,A BC aloop,AGEQ .data ivals .word 0AAh,0BBh,0CCh • 例4-2 段定义应用举例 ;初始化数据段 ;3组数据放入.data段
汇编语言源程序: ;建立newvars命名段,保留1个单元 ;在newvars段保留7个单元 ;初始化文本段 ;1字指令(DP直接寻址) ;2字指令 ;2字指令 var2 .usect “newvars”, 1 inbuf .usect “newvars”, 7 .text mpy: LD 0Ah,B Mloop: MPY #0Ah,B BC mloop,BNOV .sect “vectors” .word 011h,033h ;建立vectors命名段 ;2组数据放入vectors命名段
第4章 汇编语言程序设计 • 汇编语言源程序经过汇编后,共建立了5个段: • .text段——文本段,段内有10个字可执行的程序代码 • .data段——已初始化的数据段,段内有7个字的数据 • vectors段——用.sect命令生成的命名段,段内有2个字 的初始化数据 • .bss段——未初始化的数据段,在存储器中为变量保留 10个存储单元 • newvars段——用.usect命令建立的命名段,为变量保 留8个存储单元
例4-2 经汇编后,得列表文件(部分): 源程序的行号 段程序 计数器 目标 代码 汇编语言 源程序 2 ********************************** 3** 汇编一个初始化表到.data段 ** 4 ********************************** 50000.data 600000011coeff .word 011h,022h,033h 0001 0022 0002 0033 7 ********************************** 8 ** 在.bss段中为变量保留空间 ** 9 ********************************** 100000.bss buffer,10 11 ********************************** 12 ** .bss结束后仍然在.data 段中 ** 13 ********************************** 140003 0123prt .word 0123h
源程序的行号 段程序 计数器 目标 代码 汇编语言 源程序 15 ********************************** 16 ** 汇编代码到.text段 ** 17 ********************************** 180000.text 190000100fadd:LD 0Fh,A;DP直接寻址 200001f010aloop: SUB #1, A 00020001 210003 f842BC aloop,AGEQ 00040001’ (’ : relocatable internal reference) 22 ********************************** 23 ** 汇编另一个初始化表到.data段 24 ********************************** 250004.data 26000400aaivals .word 0AAh,0BBh,0CCh 0005 00bb 000600cc 27 ********************************** 28 ** 为更多的变量定义另一个段 ** 29 ********************************** 300000var2 .usect “newvars”,1 310001inbuf .usect “newvars”,7
例4-2 经汇编后,得列表文件(部分): 32 **************************************** 33 ** 汇编更多代码到.text段 ** 34 **************************************** 350005.text 360005 110ampy:LD 0Ah,B 37 0006f166mloop MPY #0Ah,B 0007000a 380008 f868 BC mloop,BNOV 00090006’(’ : relocatable internal reference) 39 **************************************** 40为中断向量.vectors定义一个自定义段 41 **************************************** 420000.sect “vectors” 43 00000011.word 011h,033h 00010033 源程序的行号 段程序 计数器 目标 代码 汇编语言 源程序
例4-2 经汇编后,共建立了5个段: 目标代码 行号 SPC .text 2 ******************************* 3 ** 汇编一个初始化表到.data段 ** 4 ******************************* 5 0000 .data 6 0000 0011 coeff .word 011h,022h,033h 0001 0022 0002 0033 7 ******************************* 8 ** 在.bss段中为变量保留空间 ** 9 ******************************* 10 0000 .bss buffer,10 11 ******************************* 12 ** 仍然在.data 段中 ** 13 ******************************* 14 0003 0123 prt .word 0123h 5 0000 .data 6 0000 0011 coeff .word 011h,022h,033h 6 0001 0022 6 6 0002 0033 0011 .data 6 0022 6 0033 0123 14 10 0000 .bss buffer,10 vectors .bss 没有数据 保留10个字 10 14 0003 0123 prt .word 0123h newvars
目标代码 行号 SPC 第4章 汇编语言程序设计 15 ******************************** 16 ** 汇编代码到.text段 ** 17 ******************************** 18 0000 .text 19 0000 100f add:LD 0Fh,A 20 0001 f010 aloop: SUB #1, A 0002 0001 21 0003 f842 BC aloop,AGEQ 0004 0001’ 22 ********************************** 23 ** 汇编另一个初始化表到.data 段 ** 24 ********************************** 25 0004 .data 26 0004 00aa ivals .word 0AAh,0BBh,0CCh 0005 00bb 0006 00cc 27 ******************************** 28 ** 为更多的变量定义另一个段 ** 29 ******************************** 30 0000 var2 .usect “newvars”,1 31 0001 inbuf .usect “newvars”,7 .text 19 100f 20 f010 20 0001 18 0000 .text 21 f842 21 19 0000 100f add:LD 0Fh,A 0001’ 20 0001 f010 aloop: SUB #1, A 0002 0001 21 0003 f842 BC aloop,AGEQ 0004 0001’(’ : relocatable internal reference) .data 26 00aa 25 0004 .data 26 00bb 26 0004 00aa ivals .word 0AAh,0BBh,0CCh 0005 00bb 0006 00cc 00cc 26 30 0000 var2 .usect “newvars”,1 newvars 30 保留1个字 31 0001 inbuf .usect “newvars”,7 31 保留7个字
目标代码 行号 SPC 第4章 汇编语言程序设计 .text 32 ********************************* 33 ** 汇编更多代码到.text段 ** 34 ********************************* 35 0005 .text 36 0005 110a mpy:LD 0Ah,B 37 0006 f166 mloop MPY #0Ah,B 0007 000a 38 0008 f868 BC mloop,BNOV 0009 0006’ 39 **************************************** 40 ** 为中断向量.vectors定义一个自定义段 ** 41 **************************************** 42 0000 .sect “vectors” 43 0000 0011 .word 011h,033h 0001 0033 36 110a 37 f166 35 0005 .text 37 000a 38 f868 36 0005 110a mpy:LD 0Ah,B 38 0006’ 37 0006 f166 mloop MPY #0Ah,B 0007 000a 38 0008 f868 BC mloop,BNOV 0009 0006’(’ : relocatable internal reference) vectors 43 0011 43 0033 42 0000 .sect “vectors” 43 0000 0011 .word 011h,033h 0001 0033
第4章 汇编语言程序设计 4.2.3 连接器对段的处理 • 链接器是开发’C54x器件必不可少的开发工具之一,连接器对段的处理主要完成两个功能: • 把1个或多个目标文件(文件名.obj)连接起来,产生可执行的COFF输出文件(文件名.out)。 • 按照目标系统的需要配置存储器,并将符号和段重新定位,确定输出文件的存储器地址。
第4章 汇编语言程序设计 定位(Allocation): 连接器将.text、.data、.bss等段存放到硬件系统的存储空间中去,这就是定位。 • 连接器有两种定位的方法: • 缺省定位,是指连接器对各段的定位是固定不变的方式; • 存储器映像定位,在连接前,使用连接器的伪指令MEMORY和SECTIONS等编写一个命令文件,定义出存储区域,然后,由连接器去进行存储区的映像定位。
第4章 汇编语言程序设计 用户编写的命令文件由下列4部分组成: 1)输入文件名,用来指定目标文件、归档库文件或其它命令文件。 2)连接器选项。这些选项可以编写在命令文件中,也可以使用CCS的选项或命令行实现。 3)连接器的伪指令MEMORY和SECTIONS。MEMORY指出目标存储器的配置;SECTIONS控制段的构成及其地址的分配。 4)赋值说明,用来给全局符号定义和赋值。 1. 存储器映射定位
第4章 汇编语言程序设计 2. 连接器的两个主要伪指令 • MEMORY伪指令——用来定义目标系统的存储器配置空间,包括对存储器各部分命名,以及规定它们的起始地址和长度。 • SECTIONS伪指令——用来指定链接器将输入段组合成输出段方式,以及输出段在存储器中的位置,也可用于指定子段。 • 若未使用伪指令,则连接器将使用目标处理器默认的方法将段放入存储空间。
PAGE 0 :PROG: origin = 0x0080, length = 0xFF00 PAGE 1 :DATA: origin = 0x0080, length = 0xFF80 第4章 汇编语言程序设计 1)MEMORY命令 MEMORY用来定义目标系统的存储器。它的一般语法如下: 2. 连接器的两个主要伪指令 MEMORY { PAGE 0 : name 1 [(attr)] : origin = constant , length = constant; PAGE n : name n [(attr)] : origin = constant , length = constant; }
2. 连接器的两个主要伪指令 2)SECTIONS命令 SECTIONS用来告诉连接器怎样组合输入段以及在存储器的何处存放输出段。在MEMORY指定了一种存储模式后,就应使用SECTIONS去定位。 (An output section is a section in the output file.) SECTIONS的一般语法如下: SECTIONS { name : [property, property, property,...] name : [property, property, property,...] name : [property, property, property,...] } .text: PAGE = 0 .data: PAGE = 0 .bss: PAGE = 1 .text: PAGE = 0 .data: PAGE = 0 .bss: PAGE = 1
第4章 汇编语言程序设计 • name定义一个输出文件中的输出段名,该名称不能任意指定,而是在汇编器中已经指定的段名。 • property定义段的内容以及指明它是怎样被分配的。 • property主要有下列几种: • ☆load 定义该段装载至某存储区域 • ☆run 定义该段的运行存储器区域 • ☆input sections指出构成输出段的输入段 • ☆Section type段的类型,定义特殊段的标志 • ☆Fill value用来为没有初始化的空单元填充数值
例4-3 命令文件举例 a.obj b.obj c.obj /* Input filenames */ -0 prog.out -m prog.map /* Options */ MEMORY /* MEMORY directive */ {ROM: origin = 01000h length = 0100h PAGE 1: RAM: origin = 100h length = 0100h } SECTIONS /* SECTIONS directive */ { .text: > ROM .data: > ROM .bss: > RAM }
第4章 汇编语言程序设计 3. 缺省定位(默认定位) 链接器可对多个目标文件进行链接。若链接文件中不使用MEMORY和SECTIONS命令,则为默认方式。 若采用默认链接,链接器将对多个目标文件中的各个段进行组合,形成各自的对应段,并将各个段配置到所指定的存储器中,形成可执行的目标模块。 在默认的方式下,链接器将从存储器的0080h开始,对组合后的各段进行存储器配置。
第4章 汇编语言程序设计 MEMORY { PAGE 0: PROG: origin=0x0080, length=0xFF00 PAGE 1: DATA: origin=0x0080, length=0xFF80 } SECTIONS { .text: PAGE = 0 .data: PAGE = 0 .cinit: PAGE = 0 ;仅用于C标志选项 .bss: PAGE = 1 } 例4-4 TMS320C54x的缺省定位
第4章 汇编语言程序设计 在这种缺省定位方式下,默认的存储器分配: ① 将所有.text段组合在一起,形成一个.text段,并分配到程序存储器中; ② 将多个目标文件中的.data段组合在一起,分配到紧接着.text段的程序存储空间中; ③ 将.bss段组合,配置到数据存储器中; ④ 自命名段。初始化的命名段按顺序分配到紧随.data段的程序存储器,而未初始化命名段将被配置到紧随.bss段的数据存储器中。
第4章 汇编语言程序设计 .text1 没有配置 .text .text2 .data1 .data .data2 .bss1 .bss table_1 .bss2 u_vars1 table table_2 u_vars1 u_vars2 FFT FFT 没有使用 没有使用 没有配置
汇编器的伪指令仅在汇编的过程中起作用,它们为汇编器提供一些控制和管理的信息及功能,但并不产生目标代码。汇编器的伪指令仅在汇编的过程中起作用,它们为汇编器提供一些控制和管理的信息及功能,但并不产生目标代码。 4.3 汇编器的伪指令 .text: .data: .word .bss: 汇编器伪指令可完成以下工作: • 将代码和数据汇编进指定的段 • 为未初始化的变量在存储器中保留空间 • 初始化存储器(.word,.byte, .long .... ) • 控制清单文件是否产生 • 汇编条件代码块 • 定义全局变量 • 为汇编器指定从中可以获得宏的库 • 考察符号调试信息
第4章 汇编语言程序设计 下面主要介绍以下几类汇编伪指令: ⑴段定义伪指令 如.bss、.data、.sect、.text、.usect等。 ⑵对常数(数据和存储器)进行初始化的伪指令 如.bes、.byte、.field、.float、.int、.long、.space、.string、.pstring、.xfloat、.xlong、.word等。
第4章 汇编语言程序设计 ⑶调整SPC的指令 如.align等。 (6) 定义宏的伪指令 如.macro等 ⑷ 格式化输出清单文件的伪指令 如.drlist、.drnolist等。 ⑸引用其他文件的伪指令 如.copy、.def、.global、.include、.mlib、 .ref等。
第4章 汇编语言程序设计 (7)条件汇编伪指令 如.break、.else、.elseif、.endif、.endloop、.if、.loop等。 (8)汇编时间符号伪指令 如.asg、.endstruct、.equ、.eval、.label、.set、.sruct等。 (9)混合伪指令 如.algebraic、.emsg、.end、.mmregs、.mmsg、.newblock、.sblock、.version、.vmsg等。
第4章 汇编语言程序设计 1.段定义伪指令 段定义伪指令为汇编器提供分段信息。
2.初始化常数的伪指令 用于为当前的段汇编常数值。
【例4.5】比较.byte,.int,.long,.xlong,.float,.xfloat,.word和.string伪指令。【例4.5】比较.byte,.int,.long,.xlong,.float,.xfloat,.word和.string伪指令。
.field伪指令将单个值放入当前字的指定位域。采用该伪指令可将多个字段或域打包成单个字,直到字被填满,汇编器不增加SPC。.field伪指令将单个值放入当前字的指定位域。采用该伪指令可将多个字段或域打包成单个字,直到字被填满,汇编器不增加SPC。 .field伪指令将单个值放入当前字的指定位域。采用该伪指令可将多个字段或域打包成单个字,直到字被填满,汇编器不增加SPC。 • 例4-6 该例说明.field伪指令如何将字段打包成字。假设汇编了下列代码段。 数值 位数 4 000000 6000 .field 3, 3 5 000000 6400 .field 8, 6 6 000000 6440 .field 16, 5 7 000001 0123 .field 01234h,20 000002 4000 8 000003 0000 .field 01234h,32 000004 1234