This question already has answers here:
What is the use of _start() in C?
(4 answers)
Closed 3 years ago.
Can you help me to understand how
__start
is used in C internally?
Is it the exact replica of the main function or is it the entry point to the compiled program?
Just wondering, how its getting used?
Here is a good overview of what happens during program startup before main. In particular, it shows that __start is the actual entry point to your program from OS viewpoint.
It is the very first address from which the instruction pointer will start counting in your program.
The code there invokes some C runtime library routines just to do some housekeeping, then call your main, and then bring things down and call exit with whatever exit code main returned.
A picture is worth a thousand words:
As per C/C++ standard, main() is the starting point of a program. If you're using GCC, _start function is the entry point of a C program which makes a call to main(). The main job of _start() function is to perform a few initialization tasks.
// $ gcc program_entry.c -nostartfiles
// $ ./a.out
// custom program entry
#include <stdio.h>
#include <stdlib.h>
void program_entry(void);
void
_start(void)
{
program_entry();
}
void
program_entry(void)
{
printf("custom program entry\n");
exit(0);
}
If you want, the program entry can also be compiled with -e switch in GCC.
// $ gcc program_entry.c -e __start
// $ ./a.out
// custom program entr
#include <stdio.h>
void program_entry(void);
void
_start(void)
{
program_entry();
}
void
program_entry(void)
{
printf("custom program entry\n");
}
_start is a operating system function....which is entry point for any program...as our compiler knows about main(main is not pre defined function it is user defined but all the compiler knows about them) this _start function will call main and from that point our program enters in CPU
Related
For what I understand, if there are more than one program using a shared library, the shared library won't get unloaded untill all program finishes.
I am reading The Linux Programming Interface:
42.4 Initialization and Finalization Functions It is possible to define one or more functions that are executed automatically when a
shared library is loaded and unloaded. This allows us to perform
initialization and finalization actions when working with shared
libraries. Initialization and finalization functions are executed
regardless of whether the library is loaded automatically or loaded
explicitly using the dlopen interface (Section 42.1).
Initialization and finalization functions are defined using the gcc
constructor and destructor attributes. Each function that is to be
executed when the library is loaded should be defined as follows:
void __attribute__ ((constructor)) some_name_load(void)
{
/* Initialization code */
}
Unload functions are similarly defined:
void __attribute__ ((destructor)) some_name_unload(void)
{
/* Finalization code */
} The function names `some_name_load()` and `some_name_unload()` can be replaced by any desired names. ....
Then I wrote 3 files to test:
foo.c
#include <stdio.h>
void __attribute__((constructor)) call_me_when_load(void){
printf("Loading....\n");
}
void __attribute__((destructor)) call_me_when_unload(void){
printf("Unloading...\n");
}
int xyz(int a ){
return a + 3;
}
main.c
#include <stdio.h>
#include <unistd.h>
int main(){
int xyz(int);
int b;
for(int i = 0;i < 1; i++){
b = xyz(i);
printf("xyz(i) is: %d\n", b);
}
}
main_while_sleep.c
#include <stdio.h>
#include <unistd.h>
int main(){
int xyz(int);
int b;
for(int i = 0;i < 10; i++){
b = xyz(i);
sleep(1);
printf("xyz(i) is: %d\n", b);
}
}
Then I compile a shared library and 2 executables:
gcc -g -Wall -fPIC -shared -o libdemo.so foo.c
gcc -g -Wall -o main main.c libdemo.so
gcc -g -Wall -o main_while_sleep main_while_sleep.c libdemo.so
finally run LD_LIBRARY_PATH=. ./main_while_sleep in a shell and run LD_LIBRARY_PATH=. ./main in another:
main_while_sleep output:
Loading....
xyz(i) is: 3
xyz(i) is: 4
xyz(i) is: 5
xyz(i) is: 6
xyz(i) is: 7
xyz(i) is: 8
xyz(i) is: 9
xyz(i) is: 10
xyz(i) is: 11
xyz(i) is: 12
Unloading...
main output:
Loading....
xyz(i) is: 3
Unloading...
My question is, while main_while_sleep is not finished, why Unloading is printed in main, which indicates the shared library has been unloaded? The shared library shouldn't be unloaded yet, main_while_sleep is still running!
Do I get something wrong?
My question is, while main_while_sleep is not finished, why Unloading is printed in main, which indicates the shared library has been unloaded? The shared library shouldn't be unloaded yet, main_while_sleep is still running!
You are confusing/conflating initialization/deinitialization with load/unload.
A constructor is an initialization function that is called after a shared library has been mapped into a given process's memory.
It does not affect any other process (which is in a separate, per-process address space).
Likewise, the mapping (or unmapping) of a shared library in a given process does not affect any other process.
When a process maps a library, nothing is "loaded". When the process tries to access a memory page that is part of the shared library, it receives a page fault and the given page is mapped, the page is marked resident, and the faulting instruction is restarted.
There is much more detail in my answers:
How does mmap improve file reading speed?
Which segments are affected by a copy-on-write?
read line by line in the most efficient way *platform specific*
Is Dynamic Linker part of Kernel or GCC Library on Linux Systems?
Malloc is using 10x the amount of memory necessary
The following program copied from Quora, that print "Hello world" before main() function.
#include <stdio.h>
#include <unistd.h>
int main(void)
{
return 0;
}
void _start(void)
{
printf ("hello, world\n");
int ret = main();
_exit (ret);
}
Then, I compiled above program on Ubuntu-14.04 GCC compiler using following command
gcc -nostartfiles hello.c
And ran a.out executable file, But I got Segmentation fault (core dumped)? So, Why Segmentation fault?
_start is the real entrypoint of the executable, that is normally taken by the C runtime to initialize its stuff - including stdio -, call functions marked with the constructor attribute and then call your main entrypoint. If you take it and try to use stuff from the standard library (such as printf) you are living dangerously, because you are using stuff that hasn't been initialized yet.
What you can do, however, is to bypass the C runtime completely, and print using a straight syscall, such as write.
I've been writing an OS using this tutorial. I am at the part where
the boot loader is completed and C is used for programming (and then linked together ...). But that just as a note, I believe the problem I have is related to gcc.
I build an i386-elf cross compiler for the OS. And everything works fine, I can execute my code everything works. Except that all global variables are initialized zero, although I provided a default value.
int test_var = 1234;
// yes, void main() is correct (the boot-loader will call this)
void main() {}
If I debug this code with GDB, I get: (gcc-7.1.0, target: i328-elf)
(gdb) b main
Breakpoint 1 at 0x1554: file src/kernel/main.c, line 11.
(gdb) c
Continuing.
Breakpoint 1, main () at src/kernel/main.c:11
11 void main() {
(gdb) p test_var
$1 = 0
If i run the same code on my local machine (gcc-6.3.0, target: x86_64), it prints 1234.
My question is: Did I misconfigure gcc, is this a mistake in my OS, is this a known problem? I couldn't find anything about it.
My entire source-code: link
I use the following commands to compile my stuff:
# ...
i386-elf-gcc -g -ffreestanding -Iinclude/ -c src/kernel/main.c -o out/kernel/main.o
# ...
i386-elf-ld -e 0x1000 -Ttext 0x1000 -o out/kernel.elf out/kernel_entry.o out/kernel/main.o # some other stuff ...
i386-elf-objcopy -O binary out/kernel.elf out/kernel.bin
cat out/boot.bin out/kernel.bin > out/os.bin
qemu-system-i386 -drive "format=raw,file=out/os.bin"
EDIT: As #EugeneSh. suggested here some logic to make sure, that it's not removed:
#include <cpu/types.h>
#include <cpu/isr.h>
#include <kernel/print.h>
#include <driver/vga.h>
int test_var = 1234;
void main() {
vga_text_init();
switch (test_var) {
case 1234: print("That's correct"); break;
case 0: print("It's zero"); break;
// I don't have a method like atoi() in place, I would use
// GDB to get the value
default: print("It's something else");
}
}
Sadly it prints It's zero
Compiler never clears uninitialized global variables to zero, its logic in built inside loader,
So when you allocate memory for data segment then it size contains bss section also. So you have to check bss section offset, alignment & size withing data segment and memset() them to '0'.
As you are writing your OS so may be all the library routines are not available so better write memset() function using assembly.
Compiled this on Windows using GCC. It crashed immediately with Exception Code: c00000fd.
Edit : Tried compiling following code (for visible output) and it causes stackoverflow.
#include<stdio.h>
int main(void)
{
printf("Hello World\n");
return main();
}
Output -
>gcc trailORoverflow.c -o trailORoverflow.exe
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
It keeps printing Hello World for sometime and crashes.
Edit: Didn't crash with O2, O3 and -O1 -foptimize-sibling-calls optimizations.
The code you have shown will call main infinitely, and therefore will result a stack overflow. This is true in the case of any function and not specific to main. Each function call a stack frame is created in memory, and as infinite such frames is created as the recursion goes deep, you get a stackoverflow.
But if you make a proper base termination like the example as follows, for recursive calls in main then there is an interesting thing.
int main (void)
{
static int x = 100;
if (x == 0)
{
return 0;
}
x--;
printf ("%d\n", x);
main ();
return 0;
}
There is a difference in calling main recursively in C and C++ Language, and I think it is interesting to point that out. Here is a post I wrote, I am giving some explanation about it.
C++ Standards talk about these in
Section 3.6.1 Paragraph 3
Recursive calls are permitted, except to the function named main.
and Section 5.2.2 Paragraph 9
The function main shall not be used within the program. … … …
I did not find any such restriction in the C standards. What I found about recursive calls in the C99 standards in Section 6.5.2.2 Paragraph 11 is as follows
Recursive function calls shall be permitted, both directly and indirectly through any chain of other functions.
Therefore calling main recursively in C Language is deterministic. But as per C++ standards calling main from any function or recursively is not allowed.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
undefined reference to pthread_create in linux (c programming)
I am trying to implement Thread chain in Ubuntu in C. When I compile the following code, I get the errors of Undefined reference to these thread library function even though I have added the header file.I am also getting segmentation fault error. Why is that? I am not accessing some uninitialized memory anywhere in program. Here is the code:
#include <stdio.h>
#include<stdlib.h>
#include <pthread.h>
void* CreateChain(int*);
int main()
{
int num;
pthread_t tid;
scanf("Enter the number of threads to create\n %d",&num);
pthread_create(&tid,NULL,CreateChain,&num);
pthread_join(tid,NULL);
printf("Thread No. %d is terminated\n",num);
return 0;
}
void* CreateChain(int* num )
{
pthread_t tid;
if(num>0)
{
pthread(&tid,NULL,CreateChain,num);
pthread_join(tid,NULL);
printf("Thread No. %d is terminated\n",*num);
}
else
return NULL;
return NULL;
}
I am getting following warnings and the Scanf prompt is not appearing for some reason.
Regards
The pthread.h header file provides a forward declaration of pthread functions. This tells the compiler than these functions exist and have a certain signature. It doesn't however tell the linker anything about where to find these functions at runtime.
To allow the linker to resolve these calls (decide where to jump to inside your code or in a different shared object), you need to link against the appropriate (pthread) library by adding
-pthread
to your build command line.
[Note that it is also possible to use -lpthread. This previous question expains why -pthread is preferable.]
There are various other issues with the code that will be worthy of attention
The scanf line should be split into printf("Enter number of threads\n");scanf("%d", &num); to get the user prompt displayed
The signature of CreateChain is wrong - it should take a void* argument instead. You can always do something like int num = *(int*)arg; inside the function to retrieve the number of threads.
The logic inside CreateChain looks wrong. You currently compare a pointer against 0 - I presume you mean to compare the number of threads instead? Also, if you don't decrement the number of threads to create somewhere, you'll end up with code that creates threads forever (or until you run out of handles depending on how the different threads get scheduled).
Try compiling like this below :
gcc -Wall -pthread test.c -o test.out
-pthread is an option to tell linker explicitly to resolve the symbols related to <pthread.h>
add -lpthread
gcc -o test test.c -lpthread