Why is stdlib required to link programs? [duplicate] - c

This question already has answers here:
What is the use of _start() in C?
(4 answers)
Closed 6 years ago.
Take the following C program:
int main(){}
It's not using anything from the C standard library.
I assumed we could disable linkage through -nostdlib.
However, this results in the following error:
$ gcc -nostdlib -o main main.c
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400150
Can someone clarify what the _start symbol is and who is responsible for providing it?
How would one go about using -nostdlib?
Per the docs, I have also tried:
$ gcc -nostdlib -o main main.c -lgcc
Same behaviour is seen with clang.

_start is the entry point of the program, cf. this answer. The libc contains a little stub that reads the command line arguments off the place where the operating system puts them and then calls main. Thus, it is required to link against the libc in order to run a normal C program on a normal platform.
You can try to write a program without the libc, but then you have to provide your own _start. You can't do much though, you can't even return as there is nothing you return to. Your only option is to use assembly to painstakingly recreate the parts of the libc you need, like the _exit function.

Related

Using stdlib.h functions directly in assembly

I have to do an assembly (x86) program that takes 2 long numbers from user input, adds them using a function and then prints the result. When I use the read syscall I get a string in ASCII hex code and I can't add the numbers like that. So I wanted to use atol that is a function of stdlib.h to convert the string to long. How can I include libraries in assembly? Is there another way to do this?
I have already tried:
.file "stdlib.h" (I have the lib in the current directory)
error: undefined reference to atol'
compiling stdlib.h with the .s file together using clang
error: stdlib.h: file not recognized: File format not recognized
making a .c file with only #include<stdlib.h> and compiling it with the .s file
error: undefined reference to `atol'
the comads I run are
clang function.s -c -g
ld function.o -o function
The linker complains that atol has not been found because it is a function in the C library, but you didn't tell the linker to add the C library to your program during linking. To fix this, pass -lc to the linker to add the C library during linking:
ld -o function function.o -lc
It is very important that -lc goes last, otherwise the link might not work. This is because the linker picks functions from libraries in the order you specify them. When you specify -lc before function.o, it ignores the library as it doesn't need anything from it right now. Then it sees function.o with an undefined atol and doesn't find a definition, causing the link to fail.
Lastly, when you use the C library, you should start your program from the main function (i.e. rename _start to main) like a normal C program and link through the C compiler:
clang -g -o function function.s
This causes the C library to be linked in automatically and makes initialises it correctly, preventing some weird bugs. If you use any IO functions like printf from the C library, you should also end your program by calling exit so the standard IO streams are flushed correctly.
Note that the stdlib.h file is a red herring. Header files are not needed for programming in assembly. Their purpose is to tell the C compiler what the type of some functions are. This is not needed if you do not use the C compiler. The .file directive does not do what you expect it does.
You added a compilation unit (the .c file) to the project. This introduces the prototype of the functions in the included header file "stdlib.h". What you want is reference to that function. This should be introduced in the assembler file that shall use the function.
Adding a extern statement to the assembler file should do the job. You don't need the C file with the include. You will have to add the corresponding library in the linker settings. But even if you successfully link an EXE file, you probably get a problem, since some functions in the stdlib needs an initialization. You must also call the C run-time initialization function.

While gcc needs -lm for math.h but no -l for includes stdio.h, stdlib.h etc [duplicate]

This question already has answers here:
Why do you have to link the math library in C?
(14 answers)
Closed 4 years ago.
I could not found any documentation on why gcc requires -lm for math.h functions but no -l is required for stdio or stdlib functions. Why some functions require the include and the -l gcc command option, and others don't require the -l option? Any thoughts?
There are some libraries which gets linked by default.
One of those default libraries for gcc is libc.a (static) or libc.so (dynamic) (GNU standard C library), and it contains the definition of printf() and scanf() families, including others, prototyped in stdio.h or stdlib.h .
Now, to answer your question, according to the wikipedia article
Under FreeBSD and Linux,[8] the mathematical functions (as declared in math.h) are bundled separately in the mathematical library libm. If any of them are used, the linker must be given the directive -lm.
If you want to check explicitly about the libraries getting linked by deafult, you need to use -v option to check them. You can also pass -Wl,--verbose option to get even more verbose output.
If you want to restrict the default linking, you can make use of -nostdlib switch.

-lm doesnt work unless it's at the end of the command [duplicate]

This question already has answers here:
Why does the order in which libraries are linked sometimes cause errors in GCC?
(9 answers)
Closed 2 years ago.
Im currently writing a program for a uni asssessment and they have a set line to compile it, so if it doesn't work with that it won't be accepted.
They command they use is
gcc -Wall -ansi -lm program.c -o program.out
My program will not compile that way, and it'll give me a undefined referance error (Referring to my log10 using math.h library)
if i use:
gcc -Wall -ansi program.c -o program.out -lm
it works
What could be my issue?
Im using windows 10 64bit and have windows bash installed and gcc.
This would be explained if your instructors are using gold and you are using GNU ld. These are two linkers, both are part of the GNU project, and both are commonly used with GCC.
If you are using GNU ld, you get the "traditional" behavior:
The order of specifying the -L and -l options, and the order of specifying -l options with respect to pathname operands is significant.
This means that you have to put -lm after any object files and libraries that depend on it.
However, if you are using gold, the -l options may appear first.
If you have gold installed on your system, you can test it yourself.
Here is what I get:
$ gcc -lm program.c
/tmp/ccJmBjmd.o: In function `main':
program.c:(.text+0x15): undefined reference to `sin'
collect2: error: ld returned 1 exit status
But if I use gold, it works fine:
$ gcc -lm program.c -fuse-ld=gold
-lm needs to be at the end of the command, most likely in the first case with the literal the compiler is optimizing out the call to any function and therefore does not need to link against the library. This is called constant folding and for example we can see in the gcc docs on Other Built-in Functions Provided by GCC says:
GCC includes built-in versions of many of the functions in the
standard C library. The versions prefixed with __builtin_ are always
treated as having the same meaning as the C library function even if
you specify the -fno-builtin option. (see C Dialect Options) Many of
these functions are only optimized in certain cases; if they are not
optimized in a particular case, a call to the library function is
emitted.

C - Header file containing only prototypes [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 5 years ago.
I'm working on some assignement and basically we're being introduced to splitting our files up. So far, we have only really dealt with one main file.
So, I have three files - main.c, function1.c, function2.c and a header file called header.h.
According to the instructions given to us, the header file is to contain the function prototypes of the actual functions coded in function1.c and in function2.c
We are then to include the header file in each .c files.
Inside the main.c file, the two functions that were coded in function1.c and function2.c are called. However, I am getting an error saying,
main.c:(.text+0xec): undefined reference to `func1'
main.c:(.text+0x110): undefined reference to `func2'
I'm not too sure why this is happening.
I'm running Ubuntu 16.04 LTS
This looks like the linker complains about not finding the two functions.
Using function prototypes, is only a way of saying the compiler that the implementation of a function will be aviable when linking together in the final program. Gcc will then produce an object file that contains the compiled code of main and the information that the program still needs the addresses of some functions to be able to be executed. The linker (a program called by gcc) will then put together the object file of main.c with the ones of your two functions and insert the adresses of these in the machine code of your main program at the right place.
You have to compile your program using
gcc -o main main.c function1.c function2.c
so that the actual implementation of the two functions will be aviable at linking time.
Try this in GCC compiler,
gcc main.c function1.c function2.c

Trying to understand the main function with GCC and Windows

They say that main() is a function like any other function, but "marked" as an entry point inside the binary, an entry point that the operating system may find (Don't know how) and start the program from there. So, I'm trying to find out more about this function. What have I done? I created a simple .C file with this code inside:
int main(int argc, char **argv) {
return (0);
}
I saved the file, installed the GCC compiler (in Windows, MingW environment) and created a batch file like this:
gcc -c test.c -nostartfiles -nodefaultlibs -nostdlib -nostdinc -o test.o
gcc -o test.exe -nostartfiles -nodefaultlibs -nostdlib -nostdinc -s -O2 test.o
#%comspec%
I did this to obtain a very simplistic compiler and linker, no library, no header, just the compiler. So, the compiling goes well but the linking stops with this error:
test.c:(.text+0xa): undefined reference to '___main'
collect2.exe: error: Id returned 1 exit status
I thought that the main function is exported by the linker but I believed that you didn't need any library with additional information about it. But it looks like it does. In my case I supposed that it must be the standard GCC library, so I downloaded the source code of it and opened this file: libgcc2.c
Now, I don't know if that is the file where the main function is constructed to be linked by GCC. In fact, I don't understand how the main function is used by GCC. Why does the linker need the gcc standard libraries? To know what about main? I hope this has made my question quite specific and clear. Thanks!
When gcc puts together all object files (test.o) and libraries to form a binary it also prepends a small object (usually crt0.o or crt1.o), which is responsible for calling your main(). You can see what gcc is doing, when you add -v on the command line:
$ gcc -v -o test.exe test.o
crt0/crt1 does some setup and then calls into main. But the linker is finally responsible for building the executable according to the OS. With -v you can see also an option for the target system. In my case it's for Linux 64 bit: -m elf_x86_64. For your system this will be something like -m windows or -m mingw.
The error happens because you use these two options: -nodefaultlibs -nostdlib
These tell GCC that it should not link your code against libc.a/c.lib which contains the code which really calls main(). In a nutshell, every OS is slightly different and most of them don't care about C and main(). Each has their own special way to start a process and most of them are not compatible with the C API.
So the solution of the C developers was to put "glue code" into the C standard library libc.a which contains the interface which the OS expects, creates the standard C environment (setting up the memory allocation structures so malloc() will map the OS's memory management functions, set up stdio, etc) and eventually calls main()
For C developers, this means they get a libc.a for their OS (along with the compiler binaries) and they don't need to care about how the setup works.
Another source of confusion is the name of the reference. On most systems, the symbolic name of main() is _main (i.e. one underscore) while __main is the name of an internal function called by the setup code which eventually calls the real main()

Resources