How to declare RAM functions in GCC
2005-01-13 by sig5534
Yahoo Groups archive
Index last updated: 2026-04-28 23:31 UTC
Thread
2005-01-13 by sig5534
In the IAR compiler there was an attribute to declare a function to get it mapped into RAM. How is this handled in GCC? Is there some equiv attribute? Thanks, Chris.
2005-01-14 by ntfreak2000
--- In lpc2000@yahoogroups.com, "sig5534" <sig5534@h...> wrote:
>
> In the IAR compiler there was an attribute to declare a function to
> get it mapped into RAM. How is this handled in GCC? Is there some
> equiv attribute?
>
> Thanks, Chris.
Chris,
One method is to compile as normal in gcc then use objcopy to rename
the .text segment to .data.
gcc ... file.c
objcopy --rename-section .text=.data file.o
Make sure your startup file inits the data section and away you go.
The other method is to add the file to the .data section in your
linker script, eg.
.data : AT (_etext)
{
__data_start = .;
*file.o (.text*)
*(.data .data.*)
*(.gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
} >DATA
. = ALIGN(4);
This can sometimes fail if you have a *(.text*) in your text section.
You may sometimes need to use -mlong-calls gcc option or #pragma
long_calls depending the device memory.
It could probably be done with __attribute__ ((section (".."))) - not
tried this method.
Hope this helps
sjo2005-01-14 by sig5534
Thanks sjo. Exactly what I was looking for.
I'm trying to get your last method to would, using the attribute.
This is what I did for a test function:
void __attribute__((section(".data"))) IAP_Test( void ) {
U32 N;
N=IOPIN;
} // IAP_Test
When I make I get:
main.o(.text+0x150): In function `main':
/cygdrive/d/GNUARM/Projects/Vader/main.c:96: relocation truncated to
fit: R_ARM_PC24 IAP_Test
collect2: ld returned 1 exit status
D:\GNUARM\bin\make: *** [vader.elf] Error 1
The line #96 in main is where I put the call to IAP_Test(). GCC is
taking the attribute, and seems to be doing something with it, but it
is giving me this relocation error. I don't know what R_ARM_PC24 is.
Do I need to allocate extra space for this in my startup.s file?
Can you give any help on this? This would be great to get working
with this method.
Thanks, Chris.2005-01-14 by Karl Olsen
--- In lpc2000@yahoogroups.com, "sig5534" <sig5534@h...> wrote:
>
> Thanks sjo. Exactly what I was looking for.
>
> I'm trying to get your last method to would, using the attribute.
> This is what I did for a test function:
>
> void __attribute__((section(".data"))) IAP_Test( void ) {
> U32 N;
> N=IOPIN;
> } // IAP_Test
>
> When I make I get:
>
> main.o(.text+0x150): In function `main':
> /cygdrive/d/GNUARM/Projects/Vader/main.c:96: relocation truncated
to
> fit: R_ARM_PC24 IAP_Test
> collect2: ld returned 1 exit status
> D:\GNUARM\bin\make: *** [vader.elf] Error 1
>
> The line #96 in main is where I put the call to IAP_Test(). GCC is
> taking the attribute, and seems to be doing something with it, but
it
> is giving me this relocation error. I don't know what R_ARM_PC24
is.
>
> Do I need to allocate extra space for this in my startup.s file?
Nice trick of just locating the RAM function in .data.
With main() in flash and IAP_Test() in RAM, they are ~1GB apart, and
a normal BL instruction can only handle distances of up to +/- 32 MB.
Try calling it indirectly:
static void (*pramfunc)(void) = IAP_Test;
(*pramfunc)();
Karl Olsen2005-01-15 by sig5534
> Try calling it indirectly: > > static void (*pramfunc)(void) = IAP_Test; > (*pramfunc)(); > > Karl Olsen Karl, you're close but no cigar yet. I tried it, and the compiler took it, but when the call gets made I get a PreFetch Abort Excep error. The IAP_Test() func got put in RAM correctly. It is right at 0x40000000. But the long call methodology is not quite right. The "sjo" person mentioned something about another long call method. But I'm not quite sure how he meant to set that up with the pragmas. It's almost there. Anymore ideas on making the long call? Thanks, Chris.
2005-01-15 by ntfreak2000
--- In lpc2000@yahoogroups.com, "sig5534" <sig5534@h...> wrote: > > > Try calling it indirectly: > > > > static void (*pramfunc)(void) = IAP_Test; > > (*pramfunc)(); > > > > Karl Olsen > > Karl, you're close but no cigar yet. I tried it, and the compiler > took it, but when the call gets made I get a PreFetch Abort Excep > error. > > The IAP_Test() func got put in RAM correctly. It is right at > 0x40000000. But the long call methodology is not quite right. > The "sjo" person mentioned something about another long call method. > But I'm not quite sure how he meant to set that up with the pragmas. > > It's almost there. Anymore ideas on making the long call? > > Thanks, Chris. Either use gcc option -mlong-calls on the src file or #pragma long_calls void myfunc(void); #pragma no_long_calls in the header file The objcopy is the simplest and will cause the least problems, especially if you have a *(.text*) defind in your linker script. Regards sjo
2005-01-16 by sig5534
Same result. Still not working. I get the Prefetch Abort Except. When I trace it in the debugger I can see that it gets right to the call instruc: LDR PC,[R5,#0] And then it jumps to the Prefetch Abort Excep. R5 is loaded with 0x40000000 which is the right RAM area, and the debugger says the IAP_Test() routine is at that location. I can see the code is there as well in the debugger source. Everything is right but the CPU is complaining about it's pipeline. Obviously executing code in flash ROM and then jumping to RAM is entirely different types of memory. It's confusing the memory manager prefetch pipeline. There must be something I am missing. Something else is apparently necessary to tell the CPU the next instruc is in RAM. Otherwise the CPU instruc fetch fails. Why? Chris.
2005-01-16 by Richard
Looks like you found the cause. You just need to tell the CPU to flush its pipeline. In the ARM ARM book, it mentions that "The overall result is that code which writes one or more instructions to memory and then executes them (know as self modifying code) cannot be executed reliably on ARM processors without special precautions..." and then "Each implementation therefore defines a sequence of operations that can be used in the middle of a self-modifying code sequence to make it execute reliably. This sequence is called an Instruction Memory Barrier...." So "all" you have to do is look thru the LPC2K datasheet and hope they describe what the IMB sequences are!! Good luck, At 07:05 AM 1/16/2005, sig5534 wrote: >Same result. Still not working. I get the Prefetch Abort Except. > >When I trace it in the debugger I can see that it gets right to the >call instruc: > > LDR PC,[R5,#0] > >And then it jumps to the Prefetch Abort Excep. > >R5 is loaded with 0x40000000 which is the right RAM area, and the >debugger says the IAP_Test() routine is at that location. I can see >the code is there as well in the debugger source. > >Everything is right but the CPU is complaining about it's pipeline. >Obviously executing code in flash ROM and then jumping to RAM is >entirely different types of memory. It's confusing the memory >manager prefetch pipeline. > >There must be something I am missing. Something else is apparently >necessary to tell the CPU the next instruc is in RAM. Otherwise the >CPU instruc fetch fails. Why? > >Chris. > > > > > > > >Yahoo! Groups Links > > > > // richard (This email is for mailing lists. To reach me directly, please use richard at imagecraft.com)
2005-01-16 by embeddedjanitor
From what I've seen, the self modifying code precautions in the ARMARM
are mostly relevant to CPUs with caches. With caches, particularly
with CPUs that have seperate caches for instructions and data. Clearly
if you have an instruction cache that is different from the data cache
you need to flush the caches to get the instructions to fetch
properly.
The LPC21xx does not have caches, except for the MAM, so this is not
an Ichache/Dcache issue.
I regularly use RAM-based code on ARM7s, but I achieve this by using
the linker (GNU ld) to set up the addresses and my maincrt.s copies
the RAM code from flash to RAM at start up. This is essentially what
the .data thing will do too.
Some things that are worth considering:
1) Try turning off the MAM to eliminate this from the set of variable.
2) Are you using Thumb code? If so, perhaps the .data assignment is
throwing away the thumb attributes.
3) A Prefetch Abort means that there is no memory available at the
address you specify (like a data abort, but for instructions).
The code
LDR PC,[R5,#0]
should be loading the pointer from this address (ie. R5 + #0 should be
a 32-bit value that is the pointer to the code).
Check that the address actually contains the **pointer** to the code
you want to execute and not the actual code itself.
Perhaps try
static const (*fnptr)(void) = IAP_Test;
...
*fnptr();
...
which should put the pointer in the literal pool and generate
different code.
In lpc2000@yahoogroups.com, Richard <richard-lists@i...> wrote:
> Looks like you found the cause. You just need to tell the CPU to
flush its
> pipeline. In the ARM ARM book, it mentions that
>
> "The overall result is that code which writes one or more
instructions to
> memory and then executes them (know as self modifying code) cannot
be
> executed reliably on ARM processors without special precautions..."
and then
>
> "Each implementation therefore defines a sequence of operations that
can be
> used in the middle of a self-modifying code sequence to make it
execute
> reliably. This sequence is called an Instruction Memory Barrier...."
>
> So "all" you have to do is look thru the LPC2K datasheet and hope
they
> describe what the IMB sequences are!!
>
> Good luck,
>
> At 07:05 AM 1/16/2005, sig5534 wrote:
>
>
>
> >Same result. Still not working. I get the Prefetch Abort Except.
> >
> >When I trace it in the debugger I can see that it gets right to the
> >call instruc:
> >
> > LDR PC,[R5,#0]
> >
> >And then it jumps to the Prefetch Abort Excep.
> >
> >R5 is loaded with 0x40000000 which is the right RAM area, and the
> >debugger says the IAP_Test() routine is at that location. I can
see
> >the code is there as well in the debugger source.
> >
> >Everything is right but the CPU is complaining about it's pipeline.
> >Obviously executing code in flash ROM and then jumping to RAM is
> >entirely different types of memory. It's confusing the memory
> >manager prefetch pipeline.
> >
> >There must be something I am missing. Something else is apparently
> >necessary to tell the CPU the next instruc is in RAM. Otherwise the
> >CPU instruc fetch fails. Why?
> >
> >Chris.
> >
> >
> >
> >
> >
> >
> >
> >Yahoo! Groups Links
> >
> >
> >
> >
>
> // richard (This email is for mailing lists. To reach me directly,
please
> use richard at imagecraft.com)2005-01-17 by sig5534
> 1) Try turning off the MAM to eliminate > this from the set of variable. Already using MAM_OFF. > 2) Are you using Thumb code? If so, perhaps the .data assignment is > throwing away the thumb attributes. Nope, 32b code. > 3) A Prefetch Abort means that there is no memory available at the > address you specify (like a data abort, but for instructions). > > The code > > LDR PC,[R5,#0] > > should be loading the pointer from this address > (ie. R5 + #0 should be a 32-bit value that is the pointer > to the code). > > Check that the address actually contains the **pointer** > to the code you want to execute and not the actual code itself. Now we're getting somewhere. I think this is the problem. I want it to jump to and execute at the 0x4000000 adr. There is no pointer there. > Perhaps try > > static const (*fnptr)(void) = IAP_Test; > ... > *fnptr(); That gives a compiler error: main.c:107: error: invalid type argument of `unary *' D:\GNUARM\bin\make: *** [main.o] Error 1 > which should put the pointer in the literal pool and generate > different code. Yeh I think this is on the right track. I need to get my C syntax correct here to generate a long jump directly rather than loading a pointer. The function is at 0x40000000 not a pointer to it. If you have any other ideas for this, please pass them on. Meanwhile I check my C books to try to figure out the needed syntax. Chris.
2005-01-17 by Richard
C syntax portion is easy: void (*func)(void) = (void (*)())0x40000000; (*func)(); At 04:17 PM 1/16/2005, sig5534 wrote: > > 1) Try turning off the MAM to eliminate > > this from the set of variable. > >Already using MAM_OFF. > > > 2) Are you using Thumb code? If so, perhaps the .data assignment is > > throwing away the thumb attributes. > >Nope, 32b code. > > > 3) A Prefetch Abort means that there is no memory available at the > > address you specify (like a data abort, but for instructions). > > > > The code > > > > LDR PC,[R5,#0] > > > > should be loading the pointer from this address > > (ie. R5 + #0 should be a 32-bit value that is the pointer > > to the code). > > > > Check that the address actually contains the **pointer** > > to the code you want to execute and not the actual code itself. > >Now we're getting somewhere. I think this is the problem. I want it >to jump to and execute at the 0x4000000 adr. There is no pointer >there. > > > Perhaps try > > > > static const (*fnptr)(void) = IAP_Test; > > ... > > *fnptr(); > >That gives a compiler error: > >main.c:107: error: invalid type argument of `unary *' >D:\GNUARM\bin\make: *** [main.o] Error 1 > > > which should put the pointer in the literal pool and generate > > different code. > >Yeh I think this is on the right track. I need to get my C syntax >correct here to generate a long jump directly rather than loading a >pointer. The function is at 0x40000000 not a pointer to it. > >If you have any other ideas for this, please pass them on. Meanwhile >I check my C books to try to figure out the needed syntax. > >Chris. > > > > > > >Yahoo! Groups Links > > > > // richard (This email is for mailing lists. To reach me directly, please use richard at imagecraft.com)
2005-01-17 by sig5534
Hold the phone, something funny is going on here. The debugger says that IAP_Test() is at adr 0x40000000. However when I look at the dissassembly I see this: pramfunc: 0x40000000 E321F0D1 DD 0xE321F0D1 ; DATA SECTION 14: return IOPIN|n; IAP_Test: 0x40000004 E59FD05C LDR SP,[PC,#+0x5c] 0x40000008 E321F0D2 MSR CPSR_c,#0xd2 0x4000000C E59FD054 LDR SP,[PC,#+0x54] 15: } 0x40000010 E321F0D7 MSR CPSR_c,#0xd7 0x40000014 E59FD04C LDR SP,[PC,#+0x4c] This looks like there is some kind of data or segment marker right at 0x40000000. However, the actual code is at 0x40000004. So it appears the adr being loaded into the PC is 0x40000000 and that does not appear to be code. What's going on here? Why did the compiler/linker do this? It is placing this RAM function before the variables. The RAM variables have been moved to 0x40000020. I'd rather have it the other way around. The RAM functions after the variables. That might solve this problem too. Any thoughts on how to get the RAM functions after the RAM variables? Do I need to define some more segments and the the linker how to order them? Chris.
2005-01-17 by Charles Manning
More below...
On Monday 17 January 2005 13:34, sig5534 wrote:
> Hold the phone, something funny is going on here. The debugger says
> that IAP_Test() is at adr 0x40000000. However when I look at the
> dissassembly I see this:
>
> pramfunc:
> 0x40000000 E321F0D1 DD 0xE321F0D1 ; DATA SECTION
> 14: return IOPIN|n;
pramfunc is supposed to be a pointer, so it should be holding 0x40000004 or
something (ie. a pointer to the actual function).
Try consting the pointer... this should shift it into the literal pool. This
will alter the code slightly and maybe make it work.
> IAP_Test:
> 0x40000004 E59FD05C LDR SP,[PC,#+0x5c]
> 0x40000008 E321F0D2 MSR CPSR_c,#0xd2
> 0x4000000C E59FD054 LDR SP,[PC,#+0x54]
> 15: }
> 0x40000010 E321F0D7 MSR CPSR_c,#0xd7
> 0x40000014 E59FD04C LDR SP,[PC,#+0x4c]
>
> This looks like there is some kind of data or segment marker right at
> 0x40000000. However, the actual code is at 0x40000004.
>
> So it appears the adr being loaded into the PC is 0x40000000 and that
> does not appear to be code.
>
> What's going on here? Why did the compiler/linker do this?
What seems strange to me is that the code you showed was
LDR PC,[R5,#0]
This is not what I'd expect unless the previous instruction was
MOV LR,PC
This would syntesize a branch and link.
I'd expect more to see something like:
MOV or LDR to get address into a register Rx
BL Rx
What version compiler/linker are you using? Could be an older broken one.
>
> It is placing this RAM function before the variables. The RAM
> variables have been moved to 0x40000020.
>
> I'd rather have it the other way around. The RAM functions after the
> variables. That might solve this problem too.
>
> Any thoughts on how to get the RAM functions after the RAM
> variables? Do I need to define some more segments and the the linker
> how to order them?
To control the placement you really need to use an ldscript and if you're
doing that you might as well then use the ldscript to do the placement for
you.
I do this with a section that looks like:
/* Code goes into internal RAM */
__textram_VMA__ = .; /* Where code is to be located */
.ram_text __textram_VMA__ : AT ( __textram_bLMA__ )
{
ramfunc.o(.text)
}
This makes a whole seperate section that I copy in maincrt.s, just like the
.data section is copied.
You could also place this at the end of the .data section and see if that
works.> > Chris. > > > > > > > Yahoo! Groups Links > > >
2005-01-17 by sig5534
YEH! I think I got it working.
The problem was in my startup.s file. I had turned off a flag before
that left my .data section init routine bypassed. So the data
section was not being init'd and therefore the pointer at 0x40000000
and the code itself at 0x40000004 were actually zeros/junk.
When I turned the .data init back on, the call is working! The
function is in RAM, the ptr is good, and it is running.
So to summarize, to get and use a function in RAM you only need to do
three things:
(1) Have an init in the startup code for the .data section.
(2) Use the __attribute__((section(".data"))) on the functions.
(3) Define function pointer variables for the functions and make
indirect calls using those.
That seems to do it. I'm sure there are other ways too.
Thanks guys. Now off to get my IAP code done.
Chris.2005-01-17 by Anton Erasmus
On 14 Jan 2005 at 19:15, sig5534 wrote:
>
>
> Thanks sjo. Exactly what I was looking for.
>
> I'm trying to get your last method to would, using the attribute.
> This is what I did for a test function:
>
> void __attribute__((section(".data"))) IAP_Test( void ) {
> U32 N;
> N=IOPIN;
> } // IAP_Test
>
> When I make I get:
>
> main.o(.text+0x150): In function `main':
> /cygdrive/d/GNUARM/Projects/Vader/main.c:96: relocation truncated to
> fit: R_ARM_PC24 IAP_Test collect2: ld returned 1 exit status
> D:\GNUARM\bin\make: *** [vader.elf] Error 1
>
> The line #96 in main is where I put the call to IAP_Test(). GCC is
> taking the attribute, and seems to be doing something with it, but it
> is giving me this relocation error. I don't know what R_ARM_PC24 is.
>
> Do I need to allocate extra space for this in my startup.s file?
>
> Can you give any help on this? This would be great to get working
> with this method.
>
> Thanks, Chris.
>
>
The following seems to work:
void foo(void) __attribute__ ((section ("data")));
void bar(void);
void foo(void)
{
}
int global1;
void bar(void)
{
foo();
}
Both function foo and global int global1 is put into the data section.
Regards
Anton Erasmus
--
A J Erasmus