I tried to declare an array of short pointers to strings (16-bits instead of default 32-bits) in GNU GCC C compiler for ARM Cortex-M0 processor to reduce flash consumption. I have about 200 strings in two language, so reducing the size of pointer from 32-bits to 16-bits could save 800 bytes of flash. It should be possible because the flash size is less than 64 kB so the high word (16-bits) of pointers to flash is constans and equal to 0x0800:
const unsigned char str1[] ="First string";const unsigned char str2[] ="Second string";const unsigned short ptrs[] = {&str1, &str2}; //this line generate error
but i got error in 3-th line
"error: initializer element is not computable at load time"
Then i tried:
const unsigned short ptr1 = (&str1 & 0xFFFF);
and i got:"error: invalid operands to binary & (have 'const unsigned char (*)[11]' and 'int')"
After many attempts i ended up in assembly:
.section .rodata.strings .align 2ptr0:ptr3: .short (str3-str0)ptr4: .short (str4-str0)str0:str3: .asciz "3-th string"str4: .asciz "4-th string"
compilation pass well, but now i have problem trying to reference pointers: ptr4 and ptr0 from C code. Trying to pass "ptr4-ptr0" as an 8-bit argument to C function:
ptr = getStringFromTable (ptr4-ptr0)
declared as:
const unsigned char* getStringFromTable (unsigned char stringIndex)
i got wrong code like this:
ldr r3, [pc, #28] ; (0x8000a78 <main+164>)ldrb r1, [r3, #0]ldr r3, [pc, #28] ; (0x8000a7c <main+168>)ldrb r3, [r3, #0]subs r1, r1, r3uxtb r1, r1bl 0x8000692 <getStringFromTable>
instead of something like this:
movs r0, #2bl 0x8000692 <getStringFromTable>
I would be grateful for any suggestion.
.....after a few days.....
Following @TonyK and @old_timer advices i finally solved the problem in the following way:in assembly i wrote:
.global str0, ptr0 .section .rodata.strings .align 2ptr0: .short (str3-str0) .short (str4-str0)str0:str3: .asciz "3-th string"str4: .asciz "4-th string"
then i declared in C:
extern unsigned short ptr0[];extern const unsigned char str0[] ;enum ptrs {ptr3, ptr4}; //automatically: ptr3=0, ptr4=1const unsigned char* getStringFromTable (enum ptrs index) { return &str0[ptr0[index]] ; }
and now this text:
ptr = getStringFromTable (ptr4)
is compiled to the correct code:
08000988: 0x00000120 movs r0, #10800098a: 0xfff745ff bl 0x8000818 <getStringFromTable>
i just have to remember to keep the order of enum ptrs
each time i will add a string to the assembly and a new item to enum ptrs