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.
Why attribute noreturn?
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.
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) }
but isnt the fact just said by declaring it as void?
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.
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 ; 0x6c64: 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.
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
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..
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
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.
OK, so it prevents main from returning to some other function?
noreturn just informs the compiler that main will not return.
If you lie, interesting things can happen.
Edit: noreturn is not restricted to main.
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.
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.