1.关于对段的定义
目标文件至少包含三个默认段:
.text 文本段 通常包含可执行代码
.data 数据段 通常包含初始化的数据
.bss 保留空间段 通常为没有初始化的变量保留空间
自定义段:
.usect 保留空间段 为没有初始化的数据保留空间的自定义段
.sect 初始化段 自定义段
.asect 初始化段
和默认段的使用相同,但它们被单独汇编。例如,重复使用.text段在目标文件中创建单个.text段,在链接时,这个.text段作为单个单元分配到存储器中。假中有一部分可执行代码(如初始化程序)不希望和.text段分配在一起,可以将它们汇编进一个自定义段,这样就可以分配在与.text段不同的地方。
不能用不同的伪指令定义相同的段。如.usect和.sect用同一个段名。
初始化段 .text .data .sect .asect
.text
.data
.sect “section name(段名)”
.asect “section name” address(地址)
当汇编器第一次遇到一个.data时,.data段为空的。跟在第一个.data伪指令后的指令被汇编进.data段,直到遇到.text、.sect、.asect。如果后面还遇到.data,则将跟在这些.data后面的语句汇编时已经存在的.data段。这样就形成了单个可被连续分配到存储器中的.data段。
.asect的伪指令的address是必需的。如果使用.asect指令继续汇编一个包含代码的绝对地址段(这里应该是指同一个段名的绝对地址段,还是说.asect只能有一个有地址参数?个人认识应该是前者),那么就不能使用地址参数。
.asect将代码从片外存储器加载到片内存储器里很有用。但已经很少使用,以属于过时的指令。
未初始化段 .bss .usect
.bss symbol(符号), size in words(字数)[blocking flag]
symbol .usect “section name(段名)”size in words,[blocking flag]
symbol:指向.bss或.usect伪指令所保留的存储空间的第一个字。这个符号与保留空间所使用的变量名相对应。这个符号可以让其化段引用,并且也可以用一个全局符号(.global)来声明。
相当于C中定义 unsigned char symbol[size in words];
Size in words:保留空间大小。
Blocking flag:可选项。如果该参数指定一个大于0的值,则汇编器会将size in words指定的字数连续存放,分配的空间不跨页面的边界,除非字数超过一页的长度,此时电影票将从一个页面边界开始。
Section name:为保留空间的自定义段的段名。0~8个字符。最多可产生32767个不同的自定义段。
和symbol有什么不同?
段名是用来汇编器联接用的,程序里用不到;而符号是地址,程序里可以引用。
自定义的段名第一个字符也可以是 . ,如:sect “.cinit”。
初始化段定义伪指令告诉汇编器停止汇编进入当前的段,而开始汇编进入指定的段,但未初始化段定义伪指令不终止当前的段而开始一个新段,它们只是简间的临时离开当前的段。所以.bss和.usect可以出现在初始化段的任何地方而不会影响它的内容。
链接器将段重新定位到目标系统的存储器映射。大多数系统包含几种存储器,使用段可以使目标存储器的使用更为有效。所有段都可独立地重新定位,可将任意段放到目标存储器任何已经分配的块。
例子:
.data
Coeff .word 011h,022h,033h
.bss var1,1
.bss buffer,10
Ptr .word 0123
.text
Add: LAC 0FH
Aloop: SBLK 1
BLEZ aloop
SACL var1,0
.data
Ivals .word 0aah,0bbh
Var2 .usect “newvars”,1
Inbuf .usect :newvars”,7
.text
ADD #0FFH
.text 7(WORDS)
.data 5
.bss 11
.newvars 8(由.usect创建的段)
在两本书中看到这个例子,其中.data段都是5个字的目标码。
Ptr .word 0123不算是.data段吗?那是什么段?为什么没有计算进去,是书上写错了?
2008-2-26
.cmd文件
由汇编器产生的COFF格式的OBJ文件中的段作为构造块,当有多个文件进行链接时,链接器会将输入段结全在一起产生可执行的COFF输出模块,然后链接器为各输出段选择存储器地址。
链接器有两条指令支持所述的功能:
(1):存储器(MEMORY)伪指令,用来定义目标系统的存储器空间。MEMORY可以定义存储器的区域,并指定起始地址和长度。
(2):段(SECTOINS)伪指令,告诉链接器如何将输入段结合成输出段并告诉链接器将输出段放在存储器的何处。
MEMORY伪指令的一般语法:
MEMORY
{
PAGE 0: name1[(attr)]rigin=constant, length=constant;
PAGE n: name1[(attr)]rigin=constant, length=constant;
}
PAGEn中的页号n最大为255。每个PAGE代表一个完全独立的地址空间。通常PAGE0为程序存储器,PAGE1为数据存储器。
Name1:存储器区间名。可包含8个字符。不同PAGE可以取同样的name1,但在同一个PAGE内区间名不可以相同。
Attr:可选项。规定存储器属性。
R,可以对存储器执行读操作
W,可以对存储器执行写操作
X,破除可以装入可执行的程序代码
I,规定可以对存储器进行初始化
Origin:起始地址。
Length:区间长度。
初始化段用SECTIONS可定位两次:装入和运行。如:一些关键的执行代码必须装在系统的ROM中,但希望在较快的RAM中运行。
未初始化段只可被定位一次。
自己写的关于LF2406A的.cmd文件
MEMORY
{
PAGE 0: VECS: origin=0h, length=40h ;中断向量表,40h~43h为安全代码
;或保留代码区,复位是0h和1h
FLASH: origin=44h, length=0ffbch ;32Kflash
SARAM: origin=8000h, length=800h ;当PON=1&&DON=0,
;SARAM映射为程序存储空间
B0: origin=ff00h, length=100h ; 256 WORD DARAM,CNF=1时
PAGE 1: MMRS: origin=0h, length=60h ;内部映射寄存器,或保留区间
B2: origin=60h, length=20h ;32 WORD DARAM
B0: origin=200h, length=100h ;256 WORD DARAM,CNF=0时
B1: origin=300h, length=100h ;256 WORD DARAM
SARAM: origin=800h, length=800h ;2K WORD SARAM,DON=1&&ON=0
PF1: origin=7000, length=230h ;外设帧1
EVA: origin=7400, length=32h ;外设帧2
EVB: origin=7500, length=32h ;外设帧3
}
内部的所有的存储器都定义过了,最后的三个PF1、EVA、EVB应该可以不用定义的,因为是这外设的寄存器映射。
SECTIONS
{
Name:[property,property,…]
Name:[property,property,…]
Name:[property,property,…]
}
Name:源程序中的段名。如.text
Property:段的属性参数。一个段的属性参数包括下列五种:
1.Load allocation,由它定义将输出段加载到存储器中的什么位置。
语法:load: allocation、allocation、>allocation (allocation是将逻辑段定位的地址说明)
例如:.text: load=0x1000 ;将输出段定位到一个特定的地址
.text: load>ROM ;将输出段定位到命名为ROM的存储区
.text: align=0x80 ;关键词align规定输出段.text定位到从地址边界0x80开始
.text: block(128) ;关键词bolck规定段必须在两个地址边界之内,如果段太
;大,就从一个地址边界开始
.text: PAGE0 ;将输出段定位到PAGE0
如果输出段只定位一个位置,帽可省去关键字load。如:.text: >ROM
如果要用到一个以上参数,可以将它们排成一行。如:.text: >ROM align 16 PAGE 2
或.text: load(ROM align(16) PAGE(2))
(地址边界是2的N次方幂的地址,如地址边界定为16,则其地址为xxx0h。)
定边界地址有用在什么情况下?
2.Run allocation,由它定义输出段在存储器的什么位置开始运行。
语法:run=allocation或run>allocation
链接器为每个输出段在目标存储器中分配两个地址:加载地址和执行地址。通常这两个地址是相同的。但如要先将程序加载到ROM,然后在RAM中以较快的速度运行。则可两次定位,如:
.fir: load=ROM,run=RAM
我用2406A,为什么LOAD PROGRAM时LOAD的地址空间为FLASH区时LOAD不进去,改成了SARAM时才可以?那这加载地址和运行地址的两次定位有什么意义呢?
3.Input sections,由它定义哪些输入段组成输出段。
语法:{input_sections}
.text: {*(.text)}
这样就把所有的.text段链接成.text段输出。 这是否就是默认属性?
也可以明确的用文件名和段名来确定输入段:
.text:
{
F1.obj (.text,sect) ;链接F1.obj的.text、.sect段
F2.obj (sect) ;这里的sect前面的点是本来就不用写还是书上的错误?
F3.obj ;链接f3.obj的所有段
}
4.Section type,用它为输出段定义特殊形式的标志
语法:Type=COPY、Type= DSECT、Type=NOLOAD
5.Fill value,当初始化段中存在未初始化的存储区间时,对其填充一指定值。
语法:fill: value 或name:…{…}=value
LF240X的默认算法:
MEMORY
{
PAGE 0: PROG: origin=100h, length=0efffh
PAGE 1: DATA: origin=300h, length=0xfcff ;从B1开始的数据存储空
;间,不包括B0,B2
}
SECTIONS
{
.txet: PAGE=0
.data : PAGE=0
.cinit: PAGE=0 ;C编译器自动生成,初始化
.bss: PAGE=1
}
书中举了个例子:
PAGE 0: PROG origin=40h, length=0FFC0h
.reset: {} >ROG PAGE 0
前面MEMORY中已经定义PROG是PAGE 0,为什么SECTOINS中还要写PAGE 0,不写是否可以?如果不同页中定义了相同的名字,又是否一定要写,如果可以不写又默认在哪个空间?如:PAGE 0: B0: origin=ff00h, length=100h ; 256 WORD DARAM,CNF=1时
PAGE 1: B0: origin=200h, length=100h ;256 WORD DARAM,CNF=0时
.vectors : { } > VECS PAGE 0 /* Interrupt vector table */
.reset : { } > VECS PAGE 0 /* Reset code
这是否是.reset接在.vectors后定位在VECS里?
如果两行位置互换,是否会在VECS上的定位也互换?
在下面文件里
.include f240regs.h
.sect ".vectors"
RSVECT B START ;reset vector
.bss CONV1,1
.text
.global _c_int0
_c_int0:CLRC CNF
START: SPLK #0000h,IMR
SPLK #0000h,GPTCON
……
.end
如上面的例子,自定义的段只有.vector,但为什么在.cmd文件里有
.vectors : { } > VECS PAGE 0 /* Interrupt vector table */
.reset : { } > VECS PAGE 0 /* Reset code */
.start : { } > PROG PAGE 0 /* Code */
其中自定义段.reset和.start在源文件里打不到,是否没有定义的段也可以写在SECTIONS里?
-o file.out
-m file.map
如果没写这,就没有输出,而非默认就有生成这两个文件。 |
|