In C programming, there are two ways to terminate a program from the main function: using return and using exit().
The exit function properly terminates a program. main is called after _start, which is the actual entry point of a C program.
In glibc, _start initializes the stack frame required for program execution, sets up command-line arguments (argc, argv) for the main function, and then calls __libc_start_main.
In __libc_start_call_main, the main function is executed and the return value is passed to exit to ensure proper program termination.
Therefore, when using return, the return value is passed to __libc_start_main, which then passes it to exit.
Similar implementations exist in other operating systems (like Windows and macOS) and different C standard libraries.
Through this mechanism, both return and exit() terminate the program properly.
This article focuses on the implementation in GNU/Linux environments, specifically using glibc.
C programs have the following mechanism in place - a program starts from _start, prepares for main's execution, and receives main's return value and uses it as an argument for exit.
Note that this mechanism is not limited to GNU/Linux.