The professional name of CMD is linker configuration file, which stores the configuration information of the linker. We call it command file for short. The key is the use of two pseudo-instructions, MEMORY and SECTIONS, which are often confusing. System problems are often related to their improper use. I will focus on them. CCS is a development environment inherited from DSP software under DOS system. The command file of CCS is the extension and development of DOS command file after a long period of time, and it has become very concise (I don’t know if TI document has detailed CMD configuration instructions). I started learning CMD from DOS, so I will also start with CMD in DOS environment:
1Command file composition
The beginning of the command file is the name of each sub-target file to be linked, so that the linker can link the corresponding target files into one file according to the sub-target file name; the next is the linker's operating instructions, which are used to configure the linker, and the next are the related statements of the two pseudo-instructions MEMORY and SECTIONS, which must be capitalized. MEMORY is used to configure the target memory, and SECTIONS is used to specify the storage location of the segment. Let's make an explanation based on the command file link.cmd in the following typical DOS environment:
file.obj //Sub-target file name 1
file2.obj //Sub-target file name 2
file3.obj //Sub-target file name 3
- o prog.out //Connector operation instructions, used to specify the output file
- m prog.m //Used to specify MAP file
MEMORY
{ omitted }
SECTIONS
{ omitted }
otherlink.cmd
If the command file link.cmd wants to call other command files such as otherlink.cmd, the file name should be placed at the last line of the command file. If it is placed at the beginning, the linker will not return to the command file from other called command files.
2 MEMORY directive
MEMORY is used to build a model of the target memory. The SECTIONS instruction can arrange the location of each segment according to this model. The MEMORY instruction can define various types of memory and capacity of the target system. The syntax of MEMORY is as follows:
MEMORY
{
PAGE 0: name1[(attr)]: origin = constant, length = constant
name1n[(attr)] : origin = constant,length = constant
PAGE 1: name2[(attr)]: origin = constant, length = constant
name2n[(attr)] : origin = constant,length = constant
PAGE n : namen[(attr)] : origin = constant,length = constant
namenn[(attr)] : origin = constant,length = constant
}
The PAGE keyword marks the independent storage space. The maximum value of the page number n is 255. In practical applications, it is generally divided into two pages, PAGE 0 program memory and PAGE 1 data memory.
name is the name of the storage interval, which shall not exceed 8 characters. The same name can appear on different pages (it is best not to do so to avoid confusion), but the same name is not allowed in one page.
The attribute identifier of attr is R for readable; W for writable; X for executable code can be loaded into the interval; I for initialization of the memory. No attribute code is written, indicating that the storage interval has the above four attributes. Basically, we all choose this writing method.
origin: omitted.
length: omitted.
The following is a simple way to write 2407 that I often use for your reference. The program starts from 0x060 to avoid the encryption bit. It is more reliable not to start from 0x0044. In this example, only the first page with the same name can be written, and the rest can be omitted, but it is at least safer to write it:
MEMORY
{
PAGE 0: VECS: origin = 0x0000, length 0x40
PAGE 0: PROG: origin = 0x0060, length 0x6000
PAGE 1: B0: origin = 0x200, length 0x100
PAGE 1: B1: origin = 0x300, length 0x100
PAGE 1: DATA: origin = 0x0860, length 0x0780
}
3 SECTIONS pseudo-instruction
The syntax of the SECTIONS directive is as follows:
SECTIONS
{
.text: {all .text input segment names} load = load address run = run address.data
: {all .data input segment names} load = load address run = run address.bss
: {all .bss input segment names} load = load address run = run address.other
: {all .other input segment names} load = load address run = run address
}
SECTIONS must be written in uppercase letters, and the following curly braces contain descriptive statements about the output segment. The description of each output segment starts with the segment name. After the segment name is the parameter description of how to organize the input segment and allocate memory to the segment:
Taking the attribute statement of the .text segment as an example, the "{all .text input segment names}" section is used to explain which sub-target file segments make up the .text segment of the connector output segment. The following is an example
SECTIONS
{
.text:{ file1.obj(.text) file2(.text) file3(.text,cinit)}
}
Indicates that the output segment .text is to be linked to file1.obj's .text, file2's .text, and file3's .text and .cinit. In CCS's SECTIONS, usually only a "{ }" with no content in the middle indicates the corresponding segments of all target files.
Next, it is explained that "load = load address run = run address" The linker allocates two addresses in the target memory for each output segment: one is the load address, and the other is the run address. Usually, the two addresses are the same, and it can be considered that the output segment has only one address. In this case, the statement "run = run address" can be omitted; but sometimes the two addresses need to be separated, such as loading the program into FLASH and then putting it into RAM for high-speed operation. This uses the separate configuration of the run address and the load address, as shown in the following example:
.const :{omitted} load = PROG run = 0x0800
The constant is loaded in the program storage area and configured to be called in RAM.
There are several ways to write "load = load address" that need to be explained. First, the "load" keyword can be omitted, "=" can be written as ">", and "load address" can be: address value, storage range name, PAGE keyword, etc., so don't be surprised when you see a statement like ".text:{ } > 0x0080". The "=" in "run = run address" can be written as ">", and there are no other simplified writing methods. Don't use them randomly.
4 Examples in CCS
The command file in CCS seems to be simplified a lot, with a lot less stuff and a lot of concise statements. First, there is no need to specify the target file for the input linker, CCS will automatically handle it by default. Secondly, the configuration command of the linker is also different from the DOS environment. If you need to understand, please find TI documents! The following is an example from Liu Heping's book. Let's see if you can understand it accurately! If you don't understand, please continue to discuss in this post! My QQ is 605507276!
-stack 40
MEMORY
{
PAGE 0 : VECS : origin = 0h , length = 40h
PVECS : origin = 40h , length = 70h
PROG : origin = 0b0h , length = 7F50h
PAGE 1 : MMRS : origin = 0h , length = 05Fh
B2 : origin = 0060h , length = 020h
B0 : origin = 0200 h , length = 100h
B1 : origin = 0300h , length = 100h
SARAM : origin = 0800h , length = 0800h
EXT : origin = 8000h , length = 8000h
}
SECTIONS
{
.reset : { } > VECS PAGE 0
.vectors : { } > VECS PAGE 0
.pvecs : { } > PVECS PAGE 0
.text : { } > PROG PAGE 0
.cinit : { } > PROG PAGE 0
.bss : { } > SARAM PAGE 1
.const : { } > SARAM PAGE 1
.stack : { } > B1 PAGE 1
|