EmbDev.net

Forum: ARM programming with GCC/GNU tools Prologue/Epilogue for GCC naked functions


Author: Ar Lc (al2757)
Posted on:

Rate this post
0 useful
not useful
Hi,

  Does anyone know how can I determine the gcc compiler not to insert 
any code before my function's prologue?

  This is how the function begins, I am interested if I can determine 
the compiler to generate code after the last instruction, the mov 
instruction should be after the stmdb instruction.

604:  e1a05000   mov  r5, r0
608:  ef0000d3   svc  0x000000d3
60c:  e96d50ff   stmdb  sp!, {r0, r1, r2, r3, r4, r5, r6, r7, ip, lr}^

  Thank you!

  Lucian

Author: A. K. (prx)
Posted on:

Rate this post
0 useful
not useful
It might help if you could describe what you want to achieve, to avoid 
getting the right answer to the wrong question. Also you should show the 
significant part of the source code and a little more of the resulting 
code.

Author: Ar Lc (al2757)
Posted on:

Rate this post
0 useful
not useful
Hi,

  I'm writing some system calls for a custom OS, just my free time 
project and for fun.

UINT8 LRTOS_u8MutexRelease(tstMutex *pMutex)
{
     604:  e1a05000   mov  r5, r0
  UINT8 u8ReturnValue = nE_N_OK;
  UINT8 u8TaskPrio = 0;

  /* Switch to SVC mode and disable interrupts */
  CPU_vSwitchToSvc();
     608:  ef0000d3   svc  0x000000d3

  /* Storing the USR context used to execute the current system call */
  CPU_vStoreUsrContext();
     60c:  e96d50ff   stmdb  sp!, {r0, r1, r2, r3, r4, r5, r6, r7, ip, 
lr}^

  The idea is that the last 2 instructions are the prologue of my system 
calls, a task switch can occur inside this naked function or system 
call. I need the compiler to recognize the first 2 functions as being 
the prologue of the naked function so that it never places anything 
before the last 2 instructions.

  Thank you!

  Lucian

Author: A. K. (prx)
Posted on:

Rate this post
0 useful
not useful
If you want to avoid having code placed before your manually generated 
prologue, then do not place any code there yourself. And be sure to make 
the asm statement(s) in the prologue "volatile".

So move the variables initialization beyond the prologue. And in C99 
mode you can use:

UINT8 LRTOS_u8MutexRelease(tstMutex *pMutex)
{
  /* Switch to SVC mode and disable interrupts */
  CPU_vSwitchToSvc();
  /* Storing the USR context used to execute the current system call */
  CPU_vStoreUsrContext();

  UINT8 u8ReturnValue = nE_N_OK;
  UINT8 u8TaskPrio = 0;

  ... body ...
}

Author: Ar Lc (al2757)
Posted on:

Rate this post
0 useful
not useful
Hi,

  The assembler instructions are all volatile ;-). The problem persists 
after reordering. It seems I can't make the compiler recognize my 
prologue, would have helped a #pragma or something.


  Thank you!

  Lucian

Author: A. K. (prx)
Posted on:

Rate this post
0 useful
not useful
IMHO there is no way to declare code as prologue, other than hacking 
GCC. Since the compiler choses to move the parameter into some different 
register before your asms, you may have the redesign the way you are 
dealing with the OS functions. The way you are doing it is asking for 
trouble. Even when when you find a way to get the right code tomorrow, 
the next compiler release could break your concept again.

I'd guess that there is no safe way to implement parameterized "naked" 
functions having a nontrivial body and your prologue/epilogue.

Author: Ar Lc (al2757)
Posted on:

Rate this post
0 useful
not useful
Yeah, the way I handle the functios is a little over the hand but I 
don't want to have too much overhead, that is why I use this method.

Another solution is to build another function vHack and do something 
like this

UINT8 LRTOS_u8MutexRelease(tstMutex *pMutex)
{
  /* Switch to SVC mode and disable interrupts */
  CPU_vSwitchToSvc();
     6f8:  ef0000d3   svc  0x000000d3

  /* Storing the USR context used to execute the current system call */
  CPU_vStoreUsrContext();
     6fc:  e96d50ff   stmdb  sp!, {r0, r1, r2, r3, r4, r5, r6, r7, ip, 
lr}^

  /* Prepare the scheduler call, since it will be called after the task 
is set in sleep mode */
  CPU_vPrepareSchedulerCall();
     700:  e59f3010   ldr  r3, [pc, #16]  ; 718 
<LRTOS_u8MutexRelease+0x20>
     704:  e583d000   str  sp, [r3]

  vHack(pMutex);
     708:  ebffffbd   bl  604 <vHack>

  /* Restoring the USR context used to execute the current system call 
*/
  CPU_vRestoreUsrContext();
     70c:  e8fd50ff   ldm  sp!, {r0, r1, r2, r3, r4, r5, r6, r7, ip, 
lr}^

  /* Switch back to USR mode */
  CPU_vSwitchToUsr();
     710:  ef000010   svc  0x00000010

  /* Function return, since it is a naked function it has no return */
  CPU_vFuncReturn();
     714:  e1a0f00e   mov  pc, lr

 This will add additional stack operations and I don't like it that 
much.

P.S. The concept will not be broken as long as acps is implemented and 
the naked attribute is kept, hopefully it won't be broken.

Author: A. K. (prx)
Posted on:

Rate this post
0 useful
not useful
This is only version likely to survive compiler upgrades, although you 
still could face a surprise someday. "naked" functions are a hack, 
implemented for very rare situations, so you are very much on your own 
when using them.

Author: Ar Lc (al2757)
Posted on:

Rate this post
0 useful
not useful
The problem is that I can't really build my sys calls so easy without 
having the naked attribute since I need to know where the user context 
is saved before entering the system function.
  If I let the compiler build it's own prologue I endup with system 
calls that save 4 registers, system calls that save 5 and so on, it 
would not be so easy to do a task(process) switch.

  If I go on the aproach with system calls called like the switch SVC 
with each system call and it's ID I get into trouble since I have to go 
in a very switch instruction to search for the system call.

Author: A. K. (prx)
Posted on:

Rate this post
0 useful
not useful
What's the reason for all this? Why do you switch to SVC mode instead of 
SYS mode? SVC mode has it's own R13/SP, so unless you copy the caller's 
SP you likely need a separate kernel stack for each task. Unless all 
those kernel functions are non-blocking. And if the kernel runs on the 
caller's stack, why in SVC mode?

BTW: Disabling interrupts as part of each and every kernel function this 
early makes interrupt latency suffer quite a bit.

Author: A. K. (prx)
Posted on:

Rate this post
0 useful
not useful
Ar Lc wrote:

> since I need to know where the user context
> is saved before entering the system function.

Why?

While this is the approach of big operating systems like Unix having 
separate kernel stacks, the much simpler RTOS kernels usually run the 
kernel functions on the application stack and defer saving full register 
context to the time a context switch is actually done. This is also 
quite a bit faster, since in most occurrences of OS calls a context 
switch is not actually done.

Author: Ar Lc (al2757)
Posted on:

Rate this post
0 useful
not useful
Each task has it's own stack and one SVC stack, I can acces the stack 
pointer of the USR mode and I can use it when I need to switch tasks.
 I do have to rethink a little bit the structure and the idea, maybe I 
need to change some parts, normally the interrupt latency is not that 
affected since the functions are really short(including the scheduler).
 I will have to rethink some things ;-).

P.S. You are right, I'll have to rethink the system calls, the problem 
is that in my case if I release the mutex and there is a higher priority 
task waiting for the mutex I'll have to do the context switch and place 
the lower priority task in the ready table.

Author: A. K. (prx)
Posted on:

Rate this post
0 useful
not useful
Ar Lc wrote:

> Each task has it's own stack and one SVC stack

Vague language warning. One SVC stack for each task or one SVC stack 
common to all tasks?

In the case of one SVC (kernel) stack for each task: Where exactly do 
you need to know the exakt USR context? The context switch needs the 
kernel context at time of switch, to know where to continue when 
switching back.

In the case of one common SVC stack: IMHO this only works when each and 
every kernel function is nonblocking. A rare design decision nowadays.

Author: Ar Lc (al2757)
Posted on:

Rate this post
0 useful
not useful
Sorry was not my intention(I'm not really an english native speaker, my 
apologies),

Yes, one common SVC stack in the entire system, one IRQ stack(since the 
controller I work on is an ARM9), one FIQ stack, one ABT stack, and as 
many USR stacks as needed(dependeing on the number of tasks).
At the moment I have to know the contex before the system call, it's not 
a good idea at the moment. I'll need to rethink some things, it's just a 
weekend learning experience.

Author: Ar Lc (al2757)
Posted on:

Rate this post
0 useful
not useful
Thanks for the constructive discussion. I analyzed the situation and I 
will start adapting the OS to what you said.

  Thank you!

  Lucian

Reply

Entering an e-mail address is optional. If you want to receive reply notifications by e-mail, please log in.

Rules — please read before posting

  • Post long source code as attachment, not in the text
  • Posting advertisements is forbidden.

Formatting options

  • [c]C code[/c]
  • [avrasm]AVR assembler code[/avrasm]
  • [code]code in other languages, ASCII drawings[/code]
  • [math]formula (LaTeX syntax)[/math]




Bild automatisch verkleinern, falls nötig
Note: the original post is older than 6 months. Please don't ask any new questions in this thread, but start a new one.