Why attribute noreturn?

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, please can you explain me one thing? Why is there attribute_noreturn statement in main function declaration? I mean, of course main doesent return anything in non-OS environment, but isnt the fact just said by declaring it as void? Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

pokevitek wrote:
Hi, please can you explain me one thing? Why is there attribute_noreturn statement in main function declaration? I mean, of course main doesent return anything in non-OS environment, but isnt the fact just said by declaring it as void? Thanks.
Other functions are allowed to call main.
noreturn means that said functions will never get the CPU back.
It's like calling exit.
It allows certain kinds of optimizations.
extern int fred, hank;

void gretel(void)
{
fred=2;
if(hank) main();
printf("% g\n", sin(fred));  // sin(fred)==sin(2.0)
}

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
but isnt the fact just said by declaring it as void?
Why would you think that a function declared as void would not return? It only means that it will not return a value. There is really nothing special about main as a function other than being a name reserved by the compiler.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, so it prevents main from returning to some other function? But I thought that main actually cannot be called, that it is just the point where the program starts. So, you actually can call main function from another?

Another thing I wonder, if I may ask, is main reserved for compiler OR linker? I mean, when I compile some program from multiple sources, main gets started first. But it that becouse compiler compiles it the way that start goes first, or, is main just reserved for liner to know which function goes first?

Thanks.

EDIT: In you example, gretel function will be called from main, and than called once again if hank=0? So there would be infinite loop to point where hank !=0 ?
And how in this example would attribute_noreturn help? Thanks. I am just curious.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

OK, so it prevents main from returning to some other function? But I thought that main actually cannot be called

Suggest you look at the .lss for a program you have built:

00000054 <__ctors_end>:
  54:	11 24       	eor	r1, r1
  56:	1f be       	out	0x3f, r1	; 63
  58:	cf e5       	ldi	r28, 0x5F	; 95
  5a:	d4 e0       	ldi	r29, 0x04	; 4
  5c:	de bf       	out	0x3e, r29	; 62
  5e:	cd bf       	out	0x3d, r28	; 61
  60:	0e 94 36 00 	call	0x6c	; 0x6c 
64: 0c 94 39 00 jmp 0x72 ; 0x72 <_exit>

As you can see the C runtime (the library code that runs before execution enters main) makes a CALL to main. If it should ever return there is a "capture" mechanism where it JMPs to _exit. Later in the .lss (beyond the code of your program) you will find:

00000072 <_exit>:
  72:	f8 94       	cli

00000074 <__stop_program>:
  74:	ff cf       	rjmp	.-2      	; 0x74 <__stop_program>

So this is what will happen if you ever do return from main(). It will disable interrupts then enter an infinite loop (non-breakable because of no interrupts). This can catch some folks out. If they write a program that does all the work in ISR()s and the main() just configures the interrupt sources then returns the program won't work - because of the CLI.

Quote:

Another thing I wonder, if I may ask, is main reserved for compiler OR linker?

Well it's the C standard that dictates that the entry point be called "main" (in avr-gcc/avr-as it can just as easily be an Asm label "main:") but the thing that actually implements this is, again, the C runtime. When you look at the .map file you may have noticed something like:

Linker script and memory map

LOAD c:/winavr-20100110/bin/../lib/gcc/avr/4.3.3/../../../../avr/lib/avr5/crtm16.o
LOAD test.o

Notice that as well as the test.o in this (I compiled test.c) it's been linked with a library file called crtm16.o - in this case this is the C-RunTiMe for mega16 as that's the chip I was building for. It's because it makes a CALL to a label called "main" that you must provide something in your project that satisfies this CALL or the linker will complain:

c:/winavr-20100110/bin/../lib/gcc/avr/4.3.3/../../../../avr/lib/avr5/crtm16.o:(.init9+0x0): undefined reference to `main'

which is saying that the C runtime code for mega16 has attempted to call a function called "main" but in all the .o files provided to the linker none of them provided such a function.

So the thing that actually "reserves" the name main() is this source code:

http://svn.savannah.nongnu.org/v...

This file in AVR-LibC called avr-libc/crt1/gcrt1.S is the Asm source file used to build all the different crtXXXX.o files in /winavr/avr/lib/

Near the end you will see:

	XCALL	main
	XJMP	exit

which is what actually codes the CALL to "main" (on some processors XCALL becomes RCALL and on others it is CALL). If you changed the name here and rebuilt the C runtime or added gcrt1.S to your project in place of the standard libs you could have an entry point to your C such as:

int my_own_entry_point(void) {

It would be very unwise to do this as you would be creating C programs that could not be shared with any other user or compiler.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

But I thought that main actually cannot be called, that it is just the point where the program starts. So, you actually can call main function from another?

Yes.

Adding to the above comments, main() is just a function like any other. You can call it from another. Or from itself. It's recursion in both cases..

Is it wise to do so? Probably not..

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wow, clawson, you are the pro. Thank you very much for breathtaking explanation.

I didn´t even know there is some C runtime. I mean, I supposed that every pre-main work is just not to write into ISR adres space, and when main returns, than AVR run out of program and stops, or gets stuck on end of Flash program space. From programing under Windows OS, I was told that C runtime is just a library where the specific function implementation is taken from. This makes me little confused, becouse its called RUNtime, yet it is only linked at link time, not runtime....

Can I ask one more question? what actually does this code

  54:   11 24          eor   r1, r1 
  56:   1f be          out   0x3f, r1   ; 63 
  58:   cf e5          ldi   r28, 0x5F   ; 95 
  5a:   d4 e0          ldi   r29, 0x04   ; 4 
  5c:   de bf          out   0x3e, r29   ; 62 
  5e:   cd bf          out   0x3d, r28   ; 61 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To learn I'd suggest you dig out the opcode manual and see if you can work it out yourself. However you'll get a STRONG clue if you read the gcrt1.S source I linked to above. Specifically:

	.section .init2,"ax",@progbits
	clr	__zero_reg__
	out	AVR_STATUS_ADDR, __zero_reg__
	ldi	r28,lo8(__stack)
#ifdef _HAVE_AVR_STACK_POINTER_HI
	ldi	r29,hi8(__stack)
	out	AVR_STACK_POINTER_HI_ADDR, r29
#endif	/* _HAVE_AVR_STACK_POINTER_HI */
	out	AVR_STACK_POINTER_LO_ADDR, r28

where

clr=eor (XOR a register with itself clears it)
__zero_reg__ is R1 (the second of the 32 registers)
AVR_STATUS_ADDR is the address in IO of "SREG" - the AVR CPU status flags
__stack is defined to be RAMEND for each particular AVR

The rest I think is obvious.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

pokevitek wrote:
OK, so it prevents main from returning to some other function?
Nyet.
noreturn just informs the compiler that main will not return.
If you lie, interesting things can happen.

Edit: noreturn is not restricted to main.

Moderation in all things. -- ancient proverb

Last Edited: Wed. Aug 11, 2010 - 05:23 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The attribute may cause the compiler to change the entry into main(), by stripping out any function prologue that preserves any used registers onto the stack, it may also change the call to main() to a jump to main() thus saving a few more bytes of stack.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

it may also change the call to main() to a jump to main() thus saving a few more bytes of stack.

It won't - the source of gcrt1.S is fixed and makes an "XCALL main" followed by an "XJMP exit". Short of rebuilding crtmXX.o I don't see that changing.