Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem


Loading

ARM Error: invalid literal constant: pool nee

Posted by Nobody/Anonymous on February 23, 2006
Hi,
I'm experimenting an odd problem with a FreeRTOS macro as the code grows bigger:

I'm using an ATMEL EB40A ev. board and GCC 4.02 WinARM dev. environment, and my application runs fairly good. The problem is that my code has grown big (.text is about 0x12000 bytes large) and the portSAVE_CONTEXT() and restore() macros stopped working: the compiler stops reporting:
"Error: invalid literal constant: pool needs to be closer"
several times (one per far data reference).
It looks that the referred variables like:
asm volatile ( "LDRR0, =ulCriticalNesting " );
are now too far to be directly referred (the compiler address them storing their address in local constants).
I hope to have clearly pointed out the problem but, sorry, my knowledge of the ARM assembly language is not enough to solve this problem by myself... Can anybody help me?
Thank you in advance.

RE: ARM Error: invalid literal constant: pool nee

Posted by Nobody/Anonymous on February 23, 2006
I would guess that the difference in address to the critical nesting function from where it is called is too great for encoding into the instruction but this is a guess. Try searching on the net for the error message.

RE: ARM Error: invalid literal constant: pool nee

Posted by Nobody/Anonymous on February 23, 2006
Yes, you are almost right: ulCriticalNesting is a variable, that this ARM asm code addresses using an offset based on the current PC. ARM relative indirection tange is somewhat limited and the distance between my last ISR routine (referring the variable) and the variable itself is too large to be covered by this kind of address mode.
But I'm not an ARM asm coder and I don't know how to work it out :(

RE: ARM Error: invalid literal constant: pool nee

Posted by Nobody/Anonymous on February 23, 2006
Yes, I think this is the problem too: ulCriticalNesting is a variable, that this ARM asm code addresses using an offset based on the current PC. ARM relative indirection tange is somewhat limited and the distance between my last ISR routine (referring the variable) and the variable itself is too large to be covered by this kind of address mode.
But, sorry, I'm not an ARM asm coder and I don't know how to work it out :(

RE: ARM Error: invalid literal constant: pool

Posted by Jokke on February 24, 2006
The trick is to use another addressing mode. You put the value ulCriticalNesting in aplace close to the code, and then you refer to that location. You shall be able to see examples of this in the start-up code, where they have used this tecnique. In boot.s in one of the gcc example projects you find:
ldrr1, .LC3
...
.LC3:
.word __data_beg__

From this you should be able to solve your problem.

Regards
Jokke

RE: ARM Error: invalid literal constant: pool nee

Posted by Nobody/Anonymous on February 24, 2006
Hi Jokke,
sure, I considered using this workaround (this is the trick used by the C compiler to address it), but it doesn't solve the main problem: I'd like to place this declaration INSIDE the macros themselves, by using something like the old "local" or "private" directive to avoid generating duplicate symbols... I don't know if this kind of construct exists in this asm.
Using a location OUTSIDE of the macro implies that I have to change the location name inside the macro at any usage, so I cannot use the plain macro... (but perhaps one can write a C macro substituting the "__var_addr__" symbol automagically).
Does anybody know the ARM gas syntax well enough to manage this problem?
Thank you.

RE: ARM Error: invalid literal constant: pool

Posted by Oliver on November 14, 2007
Hi,

I have the same problem, as my code size increases.

I'm using FreeRTOS 4.6.0 with WinARM-20060606, compiling for a LPC2294.

Here is an example of the error message:
arm-elf-gcc -c -mcpu=arm7tdmi-s -I. -gdwarf-2 -DXRAM_RUN -D GCC_ARM7 -D__WinARM__ -I ./import -I ./serial -I ./candrv -I ./debugTask -I ./canTask -I ./eeprom -O0 -Wall -Wextra -Wshadow -Wpointer-arith -Wbad-function-cast -Wcast-align -Wsign-compare -Waggregate-return -Wunused -I../FreeRTOS/V4.6.0/Source/include -fomit-frame-pointer -fsigned-char -save-temps -MD -MP -MF .dep/main.o.d -std=gnu99 -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations main.c -o main.o
main.s: Assembler messages:
main.s:598: Error: invalid literal constant: pool needs to be closer

The assembler listing for this reads (Line 598 is the one refering to ulCriticalNesting):
SUBLR, LR, #60
MRSR0, SPSR
STMDBLR!, {R0}
LDRR0, =ulCriticalNesting
LDRR0, [R0]
STMDBLR!, {R0}
LDRR0, =pxCurrentTCB
LDRR0, [R0]
STRLR, [R0]


Has someone already improved the portSAVE_CONTEXT / portRESTORE_CONTEXT macros to be able to handle larger code sizes?

Regards,
Oliver



RE: ARM Error: invalid literal constant: pool nee

Posted by Quantum Leaps on November 15, 2007
Try the GCC-ARM option -mlong-calls. This option replaces BL instructions with BX r? instructions. The B/BL instruction can reach only +/-4MB in Thumb in +/-32MB in ARM. The BX instruciton has access to the whole 32-bit address space (4GB).

RE: ARM Error: invalid literal constant: pool

Posted by Oliver on November 15, 2007
Hi,

thanks for your response. I tried -mlong-calls, but unfortunately it doesn't make any difference.

I'm just beginning to learn ARM ASM but as far as I understand the code, it's not a branch that fails but the instruction that's trying to load the address of the C-variable ulCriticalNesting into R0.

Regards,
Oliver

RE: ARM Error: invalid literal constant: pool

Posted by madis on November 15, 2007
Hi!

I encountered that problem in a project coded entirely in asm. I solved it by inserting .ltorg to some places the problem occured. Try googling for it and try to insert it into your code somewhere. I don't know how to insert it within c function so that arm wont execute your literals (I added it to the asm file, then it was really straightforward).

Try playing with asm() and check assembler output how it compiles. That .ltorg needs to get inserted between two functions, basically. Or you can try to branch over it within asm()... just few ideas.

Madis

RE: ARM Error: invalid literal constant: pool

Posted by Oliver on November 15, 2007
Hi,
I had no luck with the .ltorg. Maybe because it is used inside an asm() statement.
I were able to work around it manually, but this requires a branch over the data definition.

I feel that there must be a more elegant solution using input and clobber lists to the asm statement.

This might not be optimal, but it works for now:


#define portSAVE_CONTEXT() \
{ \
extern volatile void * volatile pxCurrentTCB; \
extern volatile unsigned portLONG ulCriticalNesting; \
\
asm volatile ( \
"b 2f /* skip pool */ \n\t" \
"1: \n\t" \
".word pxCurrentTCB \n\t" \
".word ulCriticalNesting \n\t" \
"2: \n\t" \
/* Push R0 as we are going to use the register. */ \
"STMDB SP!, {R0} \n\t" \
\
/* Set R0 to point to the task stack pointer. */ \
"STMDB SP,{SP}^ \n\t" \
"NOP \n\t" \
"SUB SP, SP, #4 \n\t" \
"LDMIA SP!,{R0} \n\t" \
\
/* Push the return address onto the stack. */ \
"STMDB R0!, {LR} \n\t" \
\
/* Now we have saved LR we can use it instead of R0. */ \
"MOV LR, R0 \n\t" \
\
/* Pop R0 so we can save it onto the system mode stack. */ \
"LDMIA SP!, {R0} \n\t" \
\
/* Push all the system mode registers onto the task stack. */ \
"STMDB LR,{R0-LR}^ \n\t" \
"NOP \n\t" \
"SUB LR, LR, #60 \n\t" \
\
/* Push the SPSR onto the task stack. */ \
"MRS R0, SPSR \n\t" \
"STMDB LR!, {R0} \n\t" \
\
"LDR R0, 1b+4 /* =ulCriticalNesting */ \n\t" \
"LDR R0, [R0] \n\t" \
"STMDB LR!, {R0} \n\t" \
\
/* Store the new top of stack for the task. */ \
"LDR R0, 1b /* =pxCurrentTCB */ \n\t" \
"LDR R0, [R0] \n\t" \
"STR LR, [R0] \n\t" \
); \
( void ) ulCriticalNesting; \
( void ) pxCurrentTCB; \
}


#define portRESTORE_CONTEXT() \
{ \
extern volatile void * volatile pxCurrentTCB; \
extern volatile unsigned portLONG ulCriticalNesting; \
\
asm volatile ( \
"b 2f /* skip pool */ \n\t" \
"1: \n\t" \
".word pxCurrentTCB \n\t" \
".word ulCriticalNesting \n\t" \
"2: \n\t" \
/* Set the LR to the task stack. */ \
"LDR R0, 1b /* =pxCurrentTCB */ \n\t" \
"LDR R0, [R0] \n\t" \
"LDR LR, [R0] \n\t" \
\
/* The critical nesting depth is the first item on the stack. */ \
/* Load it into the ulCriticalNesting variable. */ \
"LDR R0, 1b+4 /* =ulCriticalNesting */ \n\t" \
"LDMFD LR!, {R1} \n\t" \
"STR R1, [R0] \n\t" \
\
/* Get the SPSR from the stack. */ \
"LDMFD LR!, {R0} \n\t" \
"MSR SPSR, R0 \n\t" \
\
/* Restore all system mode registers for the task. */ \
"LDMFD LR, {R0-R14}^ \n\t" \
"NOP \n\t" \
\
/* Restore the return address. */ \
"LDR LR, [LR, #+60] \n\t" \
\
/* And return - correcting the offset in the LR to obtain the */ \
/* correct address. */ \
"SUBS PC, LR, #4 \n\t" \
); \
( void ) ulCriticalNesting; \
( void ) pxCurrentTCB; \
}

Regards,
Oliver

RE: ARM Error: invalid literal constant: pool

Posted by Oliver on April 17, 2009
Hi,

Because the code is still the same in V5.2.0 I suggest again to include the following code in the LPC2000 port (portRESTORE_CONTEXT was slightly improved compared to my last post, i moved the data behing the code, eliminating the branch).
If somebody has a more elegant solution, I would be also very happy. At least this fixes the "Error: invalid literal constant: pool needs to be closer" error that can happen if the code grows bigger.


#define portRESTORE_CONTEXT() \
{ \
extern volatile void * volatile pxCurrentTCB; \
extern volatile unsigned portLONG ulCriticalNesting; \
\
asm volatile ( \
/* Set the LR to the task stack. */ \
"LDR R0, 1f /* =pxCurrentTCB */ \n\t" \
"LDR R0, [R0] \n\t" \
"LDR LR, [R0] \n\t" \
\
/* The critical nesting depth is the first item on the stack. */ \
/* Load it into the ulCriticalNesting variable. */ \
"LDR R0, 2f /* =ulCriticalNesting */ \n\t" \
"LDMFD LR!, {R1} \n\t" \
"STR R1, [R0] \n\t" \
\
/* Get the SPSR from the stack. */ \
"LDMFD LR!, {R0} \n\t" \
"MSR SPSR, R0 \n\t" \
\
/* Restore all system mode registers for the task. */ \
"LDMFD LR, {R0-R14}^ \n\t" \
"NOP \n\t" \
\
/* Restore the return address. */ \
"LDR LR, [LR, #+60] \n\t" \
\
/* And return - correcting the offset in the LR to obtain the */ \
/* correct address. */ \
"SUBS PC, LR, #4 \n\t" \
\
/* Place the pool behind the code. This is never reached. */ \
"1: .word pxCurrentTCB \n\t" \
"2: .word ulCriticalNesting \n\t" \
); \
( void ) ulCriticalNesting; \
( void ) pxCurrentTCB; \
}
/*-----------------------------------------------------------*/

#define portSAVE_CONTEXT() \
{ \
extern volatile void * volatile pxCurrentTCB; \
extern volatile unsigned portLONG ulCriticalNesting; \
\
asm volatile ( \
"b 3f /* skip data */ \n\t" \
"1: .word pxCurrentTCB \n\t" \
"2: .word ulCriticalNesting \n\t" \
"3: \n\t" \
/* Push R0 as we are going to use the register. */ \
"STMDB SP!, {R0} \n\t" \
\
/* Set R0 to point to the task stack pointer. */ \
"STMDB SP,{SP}^ \n\t" \
"NOP \n\t" \
"SUB SP, SP, #4 \n\t" \
"LDMIA SP!,{R0} \n\t" \
\
/* Push the return address onto the stack. */ \
"STMDB R0!, {LR} \n\t" \
\
/* Now we have saved LR we can use it instead of R0. */ \
"MOV LR, R0 \n\t" \
\
/* Pop R0 so we can save it onto the system mode stack. */ \
"LDMIA SP!, {R0} \n\t" \
\
/* Push all the system mode registers onto the task stack. */ \
"STMDB LR,{R0-LR}^ \n\t" \
"NOP \n\t" \
"SUB LR, LR, #60 \n\t" \
\
/* Push the SPSR onto the task stack. */ \
"MRS R0, SPSR \n\t" \
"STMDB LR!, {R0} \n\t" \
\
"LDR R0, 2b /* =ulCriticalNesting */ \n\t" \
"LDR R0, [R0] \n\t" \
"STMDB LR!, {R0} \n\t" \
\
/* Store the new top of stack for the task. */ \
"LDR R0, 1b /* =pxCurrentTCB */ \n\t" \
"LDR R0, [R0] \n\t" \
"STR LR, [R0] \n\t" \
); \
( void ) ulCriticalNesting; \
( void ) pxCurrentTCB; \
}

Regards,
Oliver


RE: ARM Error: invalid literal constant: pool

Posted by Richard on April 17, 2009
Hi Oliver - could you post that to a feature request please? That way it won't get lost in the crowd. Thanks ;o)

Regards.

RE: ARM Error: invalid literal constant: pool nee

Posted by cynergizer on July 7, 2011
Oliver,
I ran into the exact same problem as my code size grew to 104Kbytes. I used your solution and it fixed the problem! Thank you so much for posting this (as well as what didn't work). You saved me some hurt!


[ Back to the top ]    [ About FreeRTOS ]    [ Privacy ]    [ Sitemap ]    [ ]


Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.

Latest News

NXP tweet showing LPC5500 (ARMv8-M Cortex-M33) running FreeRTOS.

Meet Richard Barry and learn about running FreeRTOS on RISC-V at FOSDEM 2019

Version 10.1.1 of the FreeRTOS kernel is available for immediate download. MIT licensed.

View a recording of the "OTA Update Security and Reliability" webinar, presented by TI and AWS.


Careers

FreeRTOS and other embedded software careers at AWS.



FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

Espressif ESP32

IAR Partner

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

Renesas

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

OpenRTOS and SafeRTOS

Xilinx Microblaze and Zynq partner