How to Write ROM library for ARM Processor?
Makefile definition:
When compiling the library, use these make file definitions
BASE_ADDRESS = base address of you Data Section
CODE_BASE_ADDRESS = base address of the Code Section
armlink -o MY_APP.axf --rwpi --rw-base BASE_ADDRESS --ro-base CODE_BASE_ADDRESS --symdefs MY_APP.sym
The output symbol file(My_APP.sym) should contain your library symbols.
If you have to include this library in any application, you have to link to this symbol file at compile time
How to call the library functions?
The r9 register stores the Base Address. Before calling the Library call you have store the content of content of r9 register.
/* Declare a pointer to the r9 register */
__global_reg(6) char *pr9_sb;
typedef void fn(void *arg);
/* Library call api*/
void arm_lib_api(fn *api_call, void *arg)
{
/*
save the current r9 register. r9 contains the
static Base address
*/
char * psaved_r9_sb = pr9_sb;
/*
get the new value for the static base address
this base address will be used for data section of the library
*/
sb = MY_BASE_ADDRESS;
/* Call the arm library api*/
api_call(arg);
/* revert to the previous r9 base address*/
pr9_sb = psaved_r9_sb;
}
Another approach to theproblem could be :
Each separate "unit" having its own static data is assigned a (small) index number (0 = the application).
ROM-based libraries would be assigned fixed index numbers (for reasons which will become obvious later).
When linking, the linker creates a static data map - basically an array, indexed by the index numbers, of pointers to the static data for each unit.
Although each individual unit has its own static data area, the linker places a pointer to this array at the start of each unit's static data.
Thus, the code the compiler inserts to access static data is similar to the existing module
relocations:
LDR rn, =variable
LDR sb, [sb, #0]
LDR sb, [sb, #4*index] ("applications" omit this instruction)
ADD rn, sb, rn ; rn now contains address of variable
Say you just wanted to add two integers together, then this could be just:
add2
LDR sb, [sb, #0]
LDR sb, [sb, #4*index]
add2_internal
LDR ry, =variable1
LDR rz, =variable2
LDR rx, [ry, sb]!
LDR rz, [rz, sb]
ADD rx, rx, rz
STR rx, [ry]
MOV pc, lr
Calls from the same unit that have accessed static data can call the alternate entry point to avoid recomputing sb if it is known to be correct already,
External calls or internal calls that do not access static data must call the top entry point.
To avoid that complexity you can have a single entry point and always compute sb when it is required, just like module relocations are done
currently.
The only problem is how to encode the special LDR instruction, of course.
You simply encode it as LDR sb, [sb, #0] with a relocation based on a special library index symbol.
The dynamic loader supplies this symbol with a different value when it loads each library.
Libraries built for ROM must have their index pre-allocated so that the linker can generate the ROM image without the need for this relocation.
This scheme gives you up to 1024 different static bases, including the application's base and the fixed ones, which should be plenty .