Customizing User-defined Sections using the MPLAB XC8 Compiler

Last modified by Microchip on 2023/11/09 09:13

__section() Specifier

A special feature of the MPLAB® XC8 Compiler gives you extra control over the sections (also known as psects) that have been defined using the __section() specifier.

Almost all data objects and functions you define in your program produce output that is placed inside a predetermined section. If you use a __section() specifier when you define an object or function, it redirects the output into a new section. You can choose the name of the new section, but the section’s specification, which is indicated by psect flags, will be identical to that of the section into which the object or function would normally have been placed. The only exception occurs when you use a __section() specifier with data objects. The new section created for these will use the same psects flags as the original section, but the class flag is omitted, so that the object can be linked in any bank.

For example, on PIC18 devices, an ordinary function you define, such as the following

int readSwitch(int no)
{ ...}

might have its output placed in a section called text0, and which might be defined by the compiler as shown here.

PSECT text0,class=CODE,reloc=2

The linker will know how to place this section in memory, and its psect flags (in this case, class and reloc) give further refinement as to how that should take place. (Any flags not specified in the PSECT directive assume a default value.)

If you were to define the same function using a __section() specifier as follows:

int section("myText") readSwitch(int no)
{ ... }

the function readSwitch() would then be placed into a section called myText, rather than text0. Having this function in a section with a unique name allows you to locate it in memory without affecting any other functions defined in your program. (The article Selective Code Protection deals with an unrelated topic, but does have examples of how you can link code that has been defined using __section().)

If you now look at the assembly produced for this function, you might see that it is located in the following section.

PSECT myText,class=CODE,reloc=2

Notice that the name of the section is now what was specified in the __section() specifier, and that the flags are identical to those used with the original section.

You can manually override some of the psect flags that are copied to the new section. Those flags are the relocsize, and limit flags. (The limit flag may not be valid for devices other than PIC18 devices.) Let’s look at how changing these flags might be useful.

The reloc flag is used to ensure that a section begins on an address that is a multiple of a value. It is typically set to the value 1, but for sections that contain executable code on a PIC18 device, it is assigned the value 2 to correctly word-align the instructions (and any new reloc value you specify must also be a multiple of 2). To override this flag value, place a asm() statement in your code outside of any function, typically towards the top of your program. So, for example, to have a function start on an address that is a multiple of 10h, place the function in a new section and change the reloc flag associated with that section as follows.

asm(“PSECT myText,reloc=10h”);

int section(“myText”) readSwitch(int no)
{ ... }

This example changes the value of the reloc flag associated with myText to be 10h. If you link the myText section into a linker class, the linker will ensure that the address it chooses is a multiple of 10h. If you explicitly link the section to an address, the linker will check the section's starting address you have specified, generating the following error if that address is not a multiple of 10h.

(455) psect "myText" not relocated on 0x10 byte boundary

Note that you only need to specify the flag that you are overriding. The section will use the inherited values for all other flags, so these should not be specified.

If you want to ensure that a section does not exceed a maximum size, you can specify a new value for the size psect flag. The following is an example of setting the size flag for the section that is being used for the above function.

asm(“PSECT myText,size=100h”);

Now if the total size of the section exceeds 100h, an error similar to the following will be produced by the linker.

(497) psect “myText” exceeds max size: 0126h > 0100h

Remember that flags apply to the entire section, and that a section is formed by collating all the compiler output from sections with the same name. If you have redirected more than one function into this section, even over multiple source files, you are ensuring that the total size of all the functions in this section is below this value.

If you have a section that must be entirely located below a certain address, you can set the limit flag, as in the following example, which this time uses a __section() specifier to redirect a variable into a new section called myBss.

asm("PSECT myBss,limit=5FFh");
int section(“myBss”) switchState[10];

If any part of the myBss section is linked above 5FFh, the linker will issue an error similar to the following.

(498) psect "myBss" exceeds address limit: 060Ah > 05FFh

Whenever you manually link sections, you should check the map file after building to ensure that everything has been positioned as you intended.