4.2.4 Using Extended Specifications

This section explains using the following extended specifications.

-

Section switch

-

Stack section creation

-

Interrupt function creation

-

Inline expansion of function

-

Inline expansion of assembly-language function

-

Entry function specification

-

Bit field order specification

-

Alignment value specification for structure members and class members

-

Allocation of a variable to the absolute address

-

Endian specification for initial values

-

Specification of function in which instructions at branch destinations are aligned for execution

-

Specification of function for generating a code for detection of stack smashing

(1)

Section Switch

#pragma section [<section type>] [D<new section name>]
<section type>: { P | C | D | B }

This extension changes the section name to be output by the compiler.

When both a section type and a new section name are specified, the section names for all functions written after the #pragma declaration are changed if the specified section type is P. If the section type is C, D, or B, the names of all sections defined after the #pragma declaration are changed.

When only a new section name is specified, the section names for the program, constant, initialized data, and uninitialized data areas after the #pragma declaration are changed. In this case, the default section name postfixed with the string specified by <new section name> is used as the new section name.

When neither a section type nor a new section name is specified, the section names for the program, constant, initialized data, and uninitialized data areas after the #pragma declaration are restored to the default section names.

The default section name for each section type is determined by the section option when specified. If the default section name is not specified by the section option, the section type name is used instead.

Examples 1.

When a section name and a section type are specified

#pragma section B Ba
int i; 	// Allocated to the Ba section
void func(void)
{
(omitted)
}
 
#pragma section B Bb
int j;	// Allocated to the Bb section
void sub(void)
{
(omitted)
}

Examples 2.

When the section type is omitted

#pragma section abc
int a; 	// Allocated to the Babc section
const int c=1; 	// Allocated to the Cabc section
void f(void)	// Allocated to the Pabc section
{
    a=c;
}
 
#pragma section
int b;	// Allocated to the B section
void g(void)	// Allocated to the P section
{
    b=c;
}

#pragma section can be declared only outside the function definition.

The section name of the following items cannot be changed by this extension. The section option needs to be used.

(1) String literal and initializers for use in the dynamic initialization of aggregates
(2) Branch table of switch statement

Up to 2045 sections can be specified by #pragma section in one file.

When specifying the section for static class member variables, be sure to specify #pragma section for both the class member declaration and definition.

Example

/*
 ** Class member declaration
 */
 
	class A
	{
		private:
		
		// No initial value specified
		#pragma section DATA
static int data_;
#pragma section
 
// Initial value specified
#pragma section TABLE
static int table_[2];
#pragma section
	};
	
	/*
	** Class member definition 
	*/
 
	// No initial value specified
	#pragma section DATA
	int A::data_;
	#pragma section
 
	// Initial value specified
	#pragma section TABLE
	int A::table_[2]={0, 1};
	#pragma section

(2)

Stack Section Creation

#pragma stacksize { si=<constant> | su=<constant> }

When si=<constant> is specified, a data section is created to be used as the stack of size <constant> with section name SI.

When su=<constant> is specified, a data section is created to be used as the stack of size <constant> with section name SU.

C source description:

#pragma stacksize si=100
#pragma stacksize su=200

Example of expanded code:

.SECTION    SI,DATA,ALIGN=4 
.BLKB       100
.SECTION    SU,DATA,ALIGN=4 
.BLKB       200

si and su can each be specified only once in a file.

<constant> must always be specified as a multiple of four.

A value from 4 to 2147483644(0x7ffffffc) is specifiable for <constant>.

(3)

Interrupt Function Creation

#pragma interrupt [(]<function name>[(<interrupt specification>[,...])][,...][)]

This extension declares an interrupt function.

A global function or a static function member can be specified for the function name.

Table 4.22 lists the interrupt specifications.

Table 4.24

Interrupt Specifications

No.

Item

Form

Options

Specifications

1

Vector table

vect=

<vector number>

Specifies the vector number for which the interrupt function address is stored.

2

Fast interrupt

fint

None

Specifies the function used for fast interrupts.

This RTFI instruction is used to return from the function.

3

Limitation on registers in interrupt function

save

None

Limits the number of registers used in the interrupt function to reduce save and restore operations.

4

Nested interrupt enable

enable

None

Sets the I flag in PSW to 1 at the beginning of the function to enable nested interrupts.

5

Accumulator saving

acc

None

Saves and restores Accumulator in the interrupt function.

6

Accumulator non-saving

no_acc

None

Does not save and restore Accumulator in the interrupt function.

An interrupt function declared by #pragma interrupt guarantees register values before and after processing (all registers used by the function are pushed onto and popped from the stack when entering and exiting the function). The RTE instruction directs execution to return from the function in most cases.

An interrupt function with no interrupt specifications is processed as a simple interrupt function.

When use of the vector table is specified (vect=), the interrupt function address is stored in the specified vector number location in the C$VECT section.

When use of fast interrupt processing is specified (fint), the RTFI instruction is used to return from the function. When the fint_register option is also specified, the registers specified through the option are used by the interrupt function without being saved or restored.

When a limitation on registers in interrupt function is specified (save), the registers that can be used in the interrupt function are limited to R1 to R5 and R14 to R15. R6 to R13 are not used and the instructions for saving and restoring them are not generated.

When enable is specified, the I flag in PSW is set to 1 at the beginning of the function to enable nested interrupts.

When Accumulator saving is specified (acc), if another function is called from the specified function or the function uses an instruction that modifies the ACC, an instruction to save and restore the ACC is generated. The save and restored code of the ACC when the ISA *1 is selected as the RXv1 or the microcomputer type is selected by the CPU *2.

When Accumulator non-saving is specified (no_acc), an instruction to save and restore the ACC is not generated.

If neither acc nor no_acc is specified, the result depends on the option settings for compilation.

A global function (in C/C++ program) or a static function member (in C++ program) can be specified as an interrupt function definition.

The function must return only void data. No return value can be specified for the return statement. If attempted, an error will be output.

Note

*1) This means a selection by the -isa option or the ISA_RX environment variable.

*2) This means a selection by the -cpu option or the CPU_RX environment variable.

Examples 1.

Correct declaration and wrong declaration

#pragma interrupt (f1, f2)
void f1(){...}	// Correct declaration.
int f2(){...}	// An error will be output 
	// because the return value is not 
	// void data.

 

Examples 2.

General interrupt function

C source description:

#pragma interrupt func
void func(){ .... }

Output code:

_func:
	PUSHM	 R1-R3	; Saves the registers used in the function.
	....
	(R1, R2, and R3 are used in the function)
	....
	POPM 	R1-R3	; Restores the registers saved at the entry.
	RTE

 

Examples 3.

Interrupt function that calls another function
In addition to the registers used in the interrupt function, the registers that are not guaranteed before and after a function call are also saved at the entry and restored at the exit.

C source description:

#pragma interrupt func
void func(){
  ...
  sub();
  ...
}

Output code:

_func:
    PUSHM R14-R15
    PUSHM R1-R5
    ...
    BSR _sub
    ...
    POPM R1-R5
    POPM R14-R15
    RTE

 

Examples 4.

Use of interrupt specification fint

C source description: Compiles with the fint_register=2 option specified

#pragma interrupt func1(fint) 
void func1(){ a=1; }    //  Interrupt function 
void func2(){ a=2; }    //  General function

Output code:

_func1:
    PUSHM R1-R3 ;  Saves the registers used in the function.
    ...         ; (Note that R12 and R13 are not saved.) 
    ...
    (R1, R2, R3, R12, and R13 are used in the function.) 
    ...
    POPM R1-R3  ;  Restores the registers saved at the entry.
    RTFI
 
_func2: 
    ...         ; In the functions without #pragma interrupt fint
    ...         ; specification, do not use R12 and R13.
    RTE

 

Examples 5.

Use of interrupt specification acc

C source description:

void func5(void);
#pragma interrupt accsaved_ih(acc)      /* Specifies acc */
void accsaved_ih(void)
{
     func5();
}

Output code:

_accsaved_ih:
     PUSHM R14-R15
     PUSHM R1-R5
     MVFACMI R4
     SHLL #10H, R4
     MVFACHI R5
     PUSHM R4-R5
     BSR _func5
     POPM R4-R5
     MVTACLO R4
     MVTACHI R5
     POPM R1-R5
     POPM R14-R15
     RTE

 

[Remarks]

Due to the specifications of the RX instruction set, only the upper 48 bits of ACC can be saved and restored with the acc flag. The lower 16 bits of ACC are not saved and restored.

Each interrupt specification can be specified only with alphabetical lowercase letters. When specified with uppercase letters, an error will occur.

When vect is used as an interrupt specification, the address of empty vectors for which there is no specification is 0. You can specify a desired address value or symbol for an address with the optimizing linkage editor. For details, refer to the descriptions on the VECT and VECTN options.

Parameters are not definable for #pragma interrupt functions. Although defining parameters for such functions does not lead to an error, values read out from the parameters are undefined.

Purpose of acc and no_acc:
acc and no_acc take into account the following purposes:

-

Solution for decrease in the interrupt response speed when compensation of ACC is performed by save_acc (no_acc)
Though the save_acc option is valid for compensation of ACC in an existing interrupt function, the interrupt response speed is degraded in some cases. Therefore, no_acc is provided as a means to disable saving and restoring of unnecessary ACC for each function independently.

-

Control of saving and restoring of ACC through source code
Explicitly selecting acc or no_acc for an interrupt function for which saving and restoring of ACC has already been considered allows saving and restoring of ACC to be defined in the source program without using the save_acc option.

(4)

Inline Expansion of Function

#pragma inline [(]<function name>[,...][)
#pragma noinline [(]<function name>[,...][)]

#pragma inline declares a function for which inline expansion is performed.

Even when the noinline option is specified, inline expansion is done for the function specified by #pragma inline.

#pragma noinline declares a function for which the inline option effect is canceled.

A global function or a static function member can be specified as a function name.

A function specified by #pragma inline or a function with specifier inline (C++ and C (C99)) are expanded where the function is called.

Example

Source file:

#pragma inline(func)
static int func (int a, int b)
{
    return (a+b)/2;
}
int x;
main()
{
    x=func(10,20);
}

Inline expansion image:

int x;
main()
{
    int func_result;
    {
        int a_1=10, b_1=20;
        func_result=(a_1+b_1)/2;
    }
    x=func_result;
}

Inline expansion will not be applied in the following functions even when #pragma inline is specified.

-

The function has variable parameters.

-

Another function is called by using the address of the function to be expanded.

#pragma inline does not guarantee inline expansion; inline expansion might not be applied due to restrictions on increasing compilation time or memory size. If inline expansion is canceled, try specifying the noscope option; inline expansion may be applied in some cases.

Specify #pragma inline before defining a function.

An external definition is generated for a function specified by #pragma inline.

When #pragma inline is specified for a static function, the function definition is deleted after inline expansion.

The C++ compiler does not create external definitions for inline-specified functions.

The C (C99) does not create external definitions for inline-specified functions unless they include extern declarations.

(5)

Inline Expansion of Assembly-Language Function

#pragma inline_asm[(]<function name>[,...][)]

This extension declares an assembly-language function for which inline expansion is performed.

The general function calling rules are also applied to the calls of assembly-language inline functions.

Example

C source description:

#pragma inline_asm func
static int func(int a, int b){
	ADD	 R2,R1	; Assembly-language description
}
main(int *p){
*p = func(10,20);
}

Output code:

_main:
   PUSH.L R6
   MOV.L R1, R6
   MOV.L #20, R2
   MOV.L #10, R1
   ADD  R2,R1; Assembly-language description
   MOV.L R1, [R6]
   MOV.L #0, R1
   RTSD #04H, R6-R6

Specify #pragma inline_asm before defining a function.

An external definition is generated for a function which is not a static function but for which #pragma inline_asm is specified.

When the registers whose values are saved and restored at the entry and exit of a function (seeTable 9.1 Rules to Use Registers) are used in an assembly-language inline function, these registers must be saved and restored at the start and end of the function.

 

[Remarks]

-

In an assembly-language inline function, use only the RX Family instruction and temporary labels. Other labels cannot be defined and assembler directives cannot be used.

-

Do not use RTS at the end of an assembly-language inline function.

-

Function members cannot be specified as function names.

-

When #pragma inline_asm is specified for a static function, the function definition is deleted after inline expansion.

-

Assembly-language descriptions are processed by the preprocessor; take special care when defining through #define a macro with the same name as an instruction or a register used in the assembly language (such as MOV or R5).

-

A stack information file handles the assembly code for a #pragma inline_asm directive as not consuming stack area. Be careful when the assembly code includes an instruction with R0 as an operand.

(6)

Entry Function Specification

#pragma entry[(]<function name>[)]

This specifies that the function specified as <function name> is handled as an entry function.

The entry function is created without any code to save and restore the contents of registers.

When #pragma stacksize is declared, the code that makes the initial setting of the stack pointer will be output at the beginning of the function.

When the base option is specified, the base register specified by the option is set up.

Example

C source description: -base=rom=R13 is specified

#pragma stacksize su=100
#pragma entry INIT
void INIT() {
:
}

Output code:

.SECTION    SU,DATA,ALIGN=4
.BLKB       100
.SECTION    P,CODE
_INIT:
MVTC        (TOPOF SU + SIZEOF SU),USP
MOV.L       #__ROM_TOP,R13

Be sure to specify #pragma entry before declaring a function.

Do not specify more than one entry function in a load module.

(7)

Bit Field Order Specification

#pragma bit_order [{left | right}]

This extension switches the order of bit field assignment.

When left is specified, bit field members are assigned from the upper-bit side. When right is specified, members are assigned from the lower-bit side.

The default is right.

If left or right is omitted, the order is determined by the option specification.

Example

C Source

Bit Assignment

#pragma bit_order right

struct tbl_r {

unsigned char a:2;

unsigned char b:3;

} x;

 

 

#pragma bit_order left

struct tbl_l {

unsigned char a:2;

unsigned char b:3;

} y;

 

// Different-size members

#pragma bit_order right

struct tbl_r {

unsigned short a:4;

unsigned char b:3;

} x

 

 

// Larger than the size of the type

#pragma bit_order right

struct tbl_r {

unsigned char a:4;

unsigned char b:5;

} x;

 

 

(8)

Alignment Value Specification for Structure Members and Class Members

#pragma pack
#pragma unpack
#pragma packoption

#pragma pack specifies the boundary alignment value for structure members and class members after the #pragma pack written in the source program.

When #pragma pack is not specified or after #pragma packoption is specified, the boundary alignment value for the structure members and class members is determined by the pack option. Table 4.23 shows #pragma pack specifications and the corresponding alignment values.

Table 4.25

#pragma pack Specifications and Corresponding Member Alignment Values

Member Type

#pragma pack

#pragma unpack

#pragma packoption or
No Extension Specification

(signed) char

1

1

1

(unsigned) short

1

2

Determined by the pack option

(unsigned) int *, (unsigned) long, (unsigned) long long, floating-point type, and pointer type

1

4

Determined by the pack option

Example

#pragma pack
struct S1 {
   char a;	/* Byte offset = 0	*/
   int b;	/* Byte offset = 1	*/
   char c;	/* Byte offset = 5	*/
} ST1;	/* Total size: 6 bytes	*/
 
#pragma unpack
struct S2 {
   char a;	/* Byte offset = 0	*/
	/* 3-byte empty area	*/
   int b;	/* Byte offset = 4	*/
   char c;	/* Byte offset = 8	*/
	/* 3-byte empty area	*/
} ST2;	/* Total size: 12 bytes	*/

The boundary alignment value for structure and class members can also be specified by the pack option. When both the option and #pragma extension specifier are specified together, the #pragma specification takes priority.

(9)

Allocation of a Variable to the Absolute Address

#pragma address [(]<variable name>=<absolute address>[,...][)]

This extension allocates the specified variable to the specified address. The compiler assigns a section for each specified variable, and the variable is allocated to the specified absolute address during linkage. If variables are specified for contiguous addresses, these variables are assigned to a single section.

Example

C source description:

#pragma address X=0x7f00
int X;
main(){
    X=0;
}

Output code:

_main:
	MOV.L       #0,R5
	MOV.L       #7F00H,R14	; 
	MOV.L       R5,[R14]
	RTS
	.SECTION    $ADDR_B_7F00
	.ORG        7F00H
	.glb        _X
_X:		; static: X
	.blkl       1

[Remarks]

-

Specify #pragma address before declaring a variable.

-

If an object that is neither a structure/union member nor a variable is specified, an error will be output.

-

If #pragma address is specified for a single variable more than one time, an error will be output.

-

A static variable that is validated by #pragma address and not referred from the source file may be removed by a compiler optimization.

-

We recommend not applying #pragma address to a variable which has an initial value but does not have the const qualifier. If this case applies for any variables, take note of the restrictions below.

-

The -rom option (RAMization of the ROM area) of the optimizing linkage editor (rlink) cannot be applied to sections containing such variables.

-

Error messages or warnings will not be displayed for code that includes such a variable.

-

When a section containing such variables is allocated to the RAM, all initial values must be written to the corresponding RAM areas when starting up the program or in advance of that.

(10)

Endian Specification for Initial Values

#pragma endian [{big | little}]

This extension specifies the endian for the area that stores static objects.

The specification of this extension is applied from the line containing #pragma endian to the end of the file or up to the line immediately before the line containing the next #pragma endian.

big specifies big endian. When the endian=little option is specified, data is assigned to the section with the section name postfixed with _B.

little specifies little endian. When the endian=big option is specified, data is assigned to the section with the section name postfixed with _L.

When big or little is omitted, endian is determined by the option specification.

Example

When the endian=little option is specified (default state)

C source description:

#pragma endian big
int A=100;	/* D_B section */
#pragma endian
int B=200;	/* D section */

Output code:

   .glb   _A
   .glb   _B
   .SECTION   D,ROMDATA,ALIGN=4
_B:
   .lword   200
   .SECTION  D_B,ROMDATA,ALIGN=4
   .ENDIAN  BIG
_A:
   .lword   100

If areas of the long long type, double type (when the dbl_size=8 option is specified), and long double type (when the dbl_size=8 option is specified) are included in objects to which #pragma endian (differed from the endian option) is applied, do not make indirect accesses to these areas using addresses or pointers. In such a case, correct operation will not be guaranteed. If a code that acquires an address in such an area is included, a warning message is displayed.

If bit fields of the long long type are included in objects to which #pragma endian (differed from the endian option) is applied, do not make writes to these areas. In such a case, correct operation will not be guaranteed.

The endian of the following items cannot be changed by this extension. The endian option needs to be used.

(1) String literal and initializers for use in the dynamic initialization of aggregates
(2) Branch table of switch statement
(3) Objects declared as external references (objects declared through extern without initialization expression)

(4) Objects specified as #pragma address

(11)

Specification of Function in which Instructions at Branch Destinations are Aligned for Execution

#pragma instalign4 [(]<function name>[(<branch destination type>)][,...][)]
#pragma instalign8 [(]<function name>[(<branch destination type>)][,...][)]
#pragma noinstalign [(]<function name>[,...][)]

Specifies the function in which instructions at branch destinations are aligned for execution.

Instruction allocation addresses in the specified function are adjusted to be aligned to 4-byte boundaries when #pragma instalign4 is specified or to 8-byte boundaries when #pragma instalign8 is specified.

In the function specified with #pragma noinstalign, alignment of allocation addresses is not adjusted.

The branch destination type should be selected from the following*:

No specification: Head of function and case and default labels of switch statement

inmostloop: Head of each inmost loop, head of function, and case and default labels of switch statement

loop: Head of each loop, head of function, and case and default labels of switch statement

Note

Alignment is adjusted only for the branch destinations listed above; alignment of the other destinations is not adjusted. For example, when loop is selected, alignment of the head of a loop is adjusted but alignment is not adjusted at the branch destination of an if statement that is used in the loop but does not generate a loop.

 

Except that each #pragma extension specification is valid only in the specified function, these specifiers work in the same way as the instalign4, instalign8, and noinstalign options. When both the options and #pragma extension specifiers are specified together, the #pragma specifications take priority.
In the code section that contains a function specified with instalign4 or instalign8, the alignment value is changed to 4 (instalign4 is specified) or 8 (instalign8 is specified). If a single code section contains both a function specified with instalign4 and that specified with instalign8, the alignment value in the code section is set to 8.
The other detailed functions of these #pragma extension specifiers are the same as those of the instalign4, instalign8, and noinstalign options; refer to the description of each option.

(12)

Specification of Function for generating a code for detection of stack smashing [Professional Edition only] [V2.04.00 or later]

#pragma stack_protector [(] function name [(num=<integer value>)] [)]

#pragma no_stack_protector [(] function name [)]

 

Generates a code for detection of stack smashing at the entry and the end of a function. A code for detection of stack smashing consists of instructions executing the three processes shown below.

(1) A 4-byte area is allocated just before (in the direction towards address 0xFFFFFFFF) the local variable area at the entry to a function, and the value specified by <number> is stored in the allocated area.

(2) At the end of the function, whether the 4-byte area in which <number> was stored has been rewritten is checked.

(3) If the 4-byte area has been rewritten in (2), the __stack_chk_fail function is called as the stack has been smashed.

A decimal number from 0 to 4294967295 should be specified in <number>. If the specification of <number> is omitted, the compiler automatically selects the number.

The __stack_chk_fail function needs to be defined by the user. It should contain postprocesses for the detected stack smashing.

Note the following items when defining the __stack_chk_fail function.

-

The only possible type of return value is void and any formal parameters not allowed.

-

It is prohibited to call the __stack_chk_fail function as a normal function.

-

The __stack_chk_fail function does not generate a code for detection of stack smashing regardless of the -stack_protector and -stack_protector_all options, and #pragma stack_protector.

-

In a C++ program, add extern "C" to the definition or the declaration for __stack_chk_fail function.

-

Prevent returning to the caller (the function where stack smashing was detected) by taking measures such as calling abort() in __stack_chk_fail function and terminating the program.

-

Do not define the function as static.

A code for detection of stack smashing is not generated for a function for which #pragma no_stack_protector has been specified regardless of the -stack_protector option and -stack_protector_all option.

If these options are used simultaneously with #pragma stack_protector, the -stack_protector option, or the -stack_protector_all option, the specification by #pragma becomes valid.

An error will occur when #pragma stack_protector and #pragma no_stack_protector are specified simultaneously for the same function within a single translation unit.

When the function specified by #pragma stack_protector is specified as any one of the following functions, an error message is output.

#pragma inline

#pragma inline_asm

#pragma entry