This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: noreturn function attribute and ret asm instruction


Thanks for the reply and your insight Jim. I have some questions though.

On Mon, 2003-08-25 at 13:30, Jim Wilson wrote:
> An extended asm isn't allowed to change the flow of control.  So this is 
> an invalid asm.

Why is it not allowed to change the flow of control ? Define "invalid".
I tried using this asm syntax in a function and I was able to change the
flow of control.

> noreturn does not suppress the ret instruction at the end of a function. 

Why not ? Shouldn't it ? Of what use is that extra "ret" then ? 

>    What it does is tell the compiler that if we call a function defined 
> as noreturn, then the call won't return.  There is no function call at

What does "the call won't return" really mean then ?

The question I have is what happens to the stack when function A makes a
call to function B (which is flagged noreturn) ? Is a return address
pushed on the stack ? I would assume one should not, since the function
called (B) will not return, thus this would not be a "call" but a "jmp".
And then the extra "ret" would be of no use if the function won't
return; and it gets in the way in what I'm trying to do. Setting a stack
frame with "enter" and having to "leave" at the end of the function is
something I'm trying to avoid also.
 
> the end of your function, so it can't be a noreturn function.  If you 
> compile with -Wall, it will tell you this.

There is no call at the end of my noreturn function, but I am trying to
call this noreturn function from another noreturn function.

In effect, what I am trying to accomplish is write a C function that can
be called without pushing a return address on the stack. And that can be
accomplished if the function is either jmp'ed to, or flagged to be
inlined. Inlined won't work for me as I need to be able to memcpy during
runtime the code generated for this function, and that may be impossible
to do if the function is inlined and further optimized differently per
case where it is inlined.

Perhaps I'm looking at the wrong direction. How do I generate "a chunk
of code" with no ret instruction at the end if I want to write that code
in C ?

Regardless, gcc should be able to see that a function flagged as
noreturn does not return if there's a jmp instruction in it that
branches somewhere else. Try running this, uncommenting only one
function at the time from main. None of A,B,C are flagged to return, but
you only get warnings for A and B when you compile it. There's no ret
instruction generated in funC, only because it calls exit(), which gcc
knows about as mentioned in the info page. How can I accomplish the same
effect when trying to write a function of my own ?

Also why does funD crash ? If funD crashes because it is flagged as
noreturn while it does return, then why is only a warning reported here
by gcc instead of an error ?


/* $ gcc -g -Wall test3.c
test3.c: In function `funA':
test3.c:14: warning: `noreturn' function does return
test3.c: In function `funB':
test3.c:23: warning: `noreturn' function does return
test3.c: In function `funD':
test3.c:40: warning: `noreturn' function does return
   $ objdump -z -d -r a.out |more
*/
#include <stdio.h>
#include <stdlib.h>

void __attribute__((noreturn)) funA (void *address)
{
  printf("funA\n");
  __asm__ __volatile__ ( "jmp *%0" 
			 : /* output */ 
			 : "m" (address) /* input */ 
			 );
}

void __attribute__((noreturn)) funB(void)
{
  printf("funB\n");
  __asm__ __volatile__ ( "jmp *%0" 
			 : /* output */ 
			 : "m" (&funB) /* input */ 
			 );
}

void __attribute__((noreturn)) funC(void)
{
  printf("funC\n");
  exit(0);
}

void funD_help()
{
  printf("funD_help\n");
}

void __attribute__((noreturn)) funD(void)
{
  printf("funD\n");
  funD_help();
}

void funE_help()
{
  printf("funE_help\n");
}

void funE()
{
  printf("funE\n");
  funE_help();
}

int main()
{
  /* This should be an infinite loop */
  //funA(&main);

  /* And so should this */
  //funB();

  /* This is not */
  //funC();

  /* Nor is this; this should not be an warning, but an error. It
crashes. */
  //funD();

  /* This is a regular function */
  //funE();
}



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]