JLI Instructions¶
Overview¶
The ARCv2 ISA provides the JLI instruction, which is two-byte
instructions that can be used to reduce code size for an application. To
make use of it, we provide two new function attributes jli_always
and
jli_fixed
which will force the compiler to call the indicated function
using a jli_s
instruction. The compiler also generates the entries in
the JLI table for the case when we use jli_always
attribute. In the
case of jli_fixed
the compiler assumes a fixed position of the
function in JLI table. Thus, the user needs to provide an assembly
file with the JLI table for the final link. This is useful when we want
to have a table in ROM and a second table in the RAM memory.
The jli instruction usage can be also forced without the need to
annotate the source code via -mjli-always
command.
Using JLI Attributes¶
The usual way of using jli calls is to use the attribute jli_always
with a function. For example:
int func (int i) __attribute__((jli_always));
int func (int i) {
return i*i;
}
int main ()
{
printf ("func returned = %d \n", func (100));
return 0;
}
Here is an assembler translation:
main:
push_s blink
st.a fp,[sp,-4] ;28
mov_s fp,sp ;4
mov_s r0,100 ;3
jli_s @__jli.func
mov_s r2,r0 ;4
mov_s r1,r2 ;4
mov_s r0,@.LC0 ;14
bl @printf;1
mov_s r2,0 ;3
mov_s r0,r2 ;4
ld.ab fp,[sp,4] ;25
pop_s blink
j_s [blink]
As we can see the call to func is done via the jli_s
instruction,
while the other calls are done using regular bl
instruction. If we
want all calls to non-local functions to be done using jli_s
then
we can use -mjli-always
compiler option. However, we need to be
careful in using this option as the JLI table can hold only 1024
entries. The compiler cannot efficiently check the number of entries as
it only has a limited view over the whole application. In this case the
GNU tool takes care of generating the JLI table, patching the jli_s
instruction with the correct entry number corresponding to the called
function, and the initialization of the jli_base
auxiliary register.
A special way to use the jli_s
instruction is for ROM patching. Because
with the jli_s
instruction function calls are made indirectly through the
JLI table, the JLI table entries can be changed to invoke alternative
functions without affecting the executable code. Thus, in this case the
location of each function called via jli instruction must be fixed and
known at compile time. To achieve this, we have introduced a new
jli_fixed
function attribute which accept a numerical parameter to
specify the function call entry in the JLI table. This attribute is GNU
specific.
Consider the following example:
int func (int i) __attribute__((jli_fixed(2)));
int func (int i)
{
return i*i;
}
int main ()
{
printf ("func returned = %d \n", func (100));
return 0;
}
Here is an assembler translation:
main:
push_s blink
st.a fp,[sp,-4] ;28
mov_s fp,sp ;4
mov_s r0,100 ;3
jli_s 2 ; @func
mov_s r2,r0 ;4
mov_s r1,r2 ;4
mov_s r0,@.LC0 ;14
bl @printf;1
mov_s r2,0 ;3
mov_s r0,r2 ;4
ld.ab fp,[sp,4] ;25
pop_s blink
j_s [blink]
As we can see now, the operand of jli_s
instruction is already resolved
and points to entry 2 in the JLI table. In this case, the compiler
does not generate the JLI table, as it needs to be provided by the user.
A JLI table can be something like this:
.section .jlitab
.align 4
JLI_table:
__jli.entry0: b entry0 ; 0
__jli.entry1: b entry1 ; 1
__jli.func: b func ; 2
The initialization of the jli_base
is again done by the crt0
. However,
in the case of RAM/ROM patching, one may want to overwrite the initial
value with a new value based on the location of a patched JLI table.
N.B. the RAM/ROM patching approach may require special startup and/or
linker scripts which are not provided.
Compatibility with MetaWare¶
In general the GNU JLI implementation is compatible with MWDT
implementation, except for the code that invokes the MetaWare runtime
initialization code that sets the JLI_BASE
register to address the JLI
table. GNU additionally introduces the jli_fixed
attribute to closely
mimic the MWDT jli_call_fixed
pragma.