Reputation: 99
I've seen code like below in a project:
extern void my_main(void) __attribute__ ((__noreturn__, asection(".main","f=ax")));
What does this do?
The project does not have a direct main()
function in it. Does the above code indicate to the compiler that my_main()
should be treated as main()
?
Also, what does the .main
memory section indicate?
Upvotes: 1
Views: 237
Reputation: 15103
What the above declaration basically does is declare an extern
function called my_main()
with no arguments.
The __attribute__
section is a GNU/LLVM attribute syntax. Attributes are basically pragmas that describe some non-standard or extended feature of the function in question - in this case, my_main()
.
There are two attributes applied to my_main()
.
__noreturn__
(search for noreturn
) indicates that the function will never return.
This is different from returning void
- in void
-type functions, calls to the function still return
at some point, even without a value. This means execution will jump/return back to the caller.
In noreturn
(a.k.a. _noreturn
or __noreturn__
) functions, this indicates that, among other things, calls to this function shouldn't add the return address to the stack, as the function itself will either exit before execution returns, or will long jump to another point in execution.
It is also used in places where adding the return address to the stack will disrupt the stack in a way that interferes with the called function (though this is rare and I've only ever seen it used for this reason once).
The second attribute, asection(".main","f=ax")
, is a little more vague. I can't seem to find specific documentation for it, but it seems more or less pretty straightforward.
What it appears to be doing is specifying a linker section as well as what appears to be a unix filemode specifying that the resulting binary is executable, though I could be wrong.
When you write native code, all functionality is placed into appropriate sections of the target binary format (e.g. ELF, Mach-O, PE, etc.) The most common sections are .text
, .rodata
, and .data
.
However, when invoking ld
, the GCC linker, you can specify a linker script to specify exactly how you want the target binary to be constructed.
This includes sections, sizes, and even the object files you want to use to make the file, specifying where they should go and their size limits.
One common misconception is that you never use ld
. This isn't the case; when you run gcc
or g++
or the clang
-family of compilers without the -c
flag, you inadvertently invoke ld
with a default linker script used to link your binaries.
Linker scripts are important especially for embedded hardware where ROM must be built to memory specification.
So back to your line of code: it places my_func()
into an arbitrary section called .main
. That's all it does. Ultimately, somewhere in your project, there is a linker script that specifies how .main
is used and where it goes.
I would imagine the goal of this code was to place my_main()
at an exact address in the target binary/executable, so whatever is using it knows the exact location of that function (asection(".main")
) and can use it as an entry point (__noreturn__
).
Upvotes: 3