RX automatic interrupt vector entry usage

From GNU Tools - Wiki
Revision as of 13:30, 17 May 2023 by Administrator (Talk | contribs) (Created page with "The GNU linked provides the '''--gc-sections''' flag, which removes unused functions from the final binary, thus reducing code size. One of the drawbacks of this technique is...")

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

The GNU linked provides the --gc-sections flag, which removes unused functions from the final binary, thus reducing code size. One of the drawbacks of this technique is that it will by-default remove all interrupt service routines (ISRs).

This is unsurprising, because ISRs are normally not referenced anywhere from within the C code (which is how the GNU linker determines what to remove). However, it is possible to inform the linker not to remove the ISRs, using one of two techniques:

  1. Marking ISR $tableentry$NN$vect auto-generated symbols with KEEP()
  1. Annotating ISR C functions with an additional section((".isr-sect")) section, and KEEP()'ing the section

1. Marking ISR $tableentry$NN$vect auto-generated symbols with KEEP()

The advantage of this approach is that it does not require changing the source code, and does not require any modification after initial set-up.

Consider the following two files:

main.c:

#include <stdio.h>

int main(void)
{
  int ret;

  ret = printf("Hello World!\r\n");

  return ret;
}

int.c:

__attribute__((interrupt(2)))
void f(void)
{
  return;
}

If we try to link the resultant object files with -Wl,--gc-sections -Wl,--print-gc-sections passed to the GCC invocation, we will find our function removed:

...
gcc_8.3.0.202204_rx_elf/bin/../lib/gcc/rx-elf/8.3.0.202204-GNURX/../../../../rx-elf/bin/ld: removing unused section '.text.f' in file 'int.o'
...

This is expected behaviour. We aren't "calling" f from anywhere, and hence the linker deduces that it is unused.

However, when the compiler compiles a function with the interrupt attribute, it will create a special symbol in the output assembly file:

	.global	_f
	.type	_f, @function
_f:
	.global	$tableentry$2$vect
$tableentry$2$vect:
	; Note: Interrupt Handler
	push.l	r10
	...

Since there are 255 possible ISR vectors, there are a finite number of these symbols that can exist. We can take advantage of this by creating a separate hand-crafted assembler file, called int-guard.s, and populating it with all possible ISR symbol names:

.section .intvecguard
.weak $tableentry$0$vect
.word $tableentry$0$vect
.weak $tableentry$1$vect
.word $tableentry$1$vect
.weak $tableentry$2$vect
.word $tableentry$2$vect
...
.weak $tableentry$255$vect
.word $tableentry$255$vect

(The weak will be explained a bit later.)

And in our linker script, at the very end we add the following line:

...
    .intvecguard :
    {
        KEEP(*(.intvecguard))
    }
}

Now the code corresponding to the ISR will be preserved in the final binary, because the dummy symbolic references in the .intvecguard section effectively mark the corresponding function as 'used'.

The reason we marked the symbols as weak, is so that the linker automatically defines the symbol if the user did not create an ISR corresponding to that particular vector. What this means is that the int-guard.s file will work without modification for all possible use cases.

2. Annotating ISR C functions with an additional section((".isr-sect")) section, and KEEP()'ing the section.

This method was documented by user "NoMaY" on the Renesas support forums. The method is as follows:

Annotate all ISR functions with an additional section((".isr-text")) attribute, e.g. If the code normally was

__attribute__((interrupt(2)))
void f(void)
{
}

Then it should become

__attribute__((interrupt(2), section(".isr-text")))
void f(void)
{
}

Next, simply mark the section as KEEP() within the .text output section of the linker script:

...
        .text 0xFFE000A0: AT(0xFFE000A0)
        {
                *(.text)
                *(.text.*)
                *(P)
                etext = .;

                KEEP(*(.isr-text))
        } > ROM
...
}