Steps of compilation - c

I am trying to compile simple Hello World C program in a sequential manner. First creating the preprocessed file, then creating the assembly file, then creating the object file and finally invoking the linker to create the ELF.
The problem is I am not able to execute the ELF being created.
I have tried following steps
gcc -E hello.c 1>hello.i
gcc -S hello.i
gcc -c hello.s
ld -o hello hello.o -lc
At this step I got a warning saying
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400260
But an executable with the name hello is created.
When I try to execute the output using
./hello
I am getting the error
bash: ./hello: No such file or directory
//hello.c contains following code
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
printf("\tHello World \n");
return (0);
}

I would suggest that you link your object files (however they are produced) with gcc, not ld.
gcc will call ld with the appropriate options, since it knows more about the source code and will create whatever is necessary for the assumptions that ld makes.

Related

I don't know how to link multiple files

I'm learning how to use header files and I have a problem while linking these 3 files:
f.c:
#include "f.h"
int getfavoritenumber(void)
{
return 3;
}
f.h:
#ifndef _f_H_
#define _f_H_
int getfavoritenumber(void);
#endif
main.c:
#include <stdio.h>
#include "f.h"
int main (void)
{
printf("%d\n", getfavoritenumber());
return 0;
}
Compiling gcc main.c -o f I get this error:
Undefined symbols for architecture x86_64:
"_getfavoritenumber", referenced from:
_main in main-7be23f.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
But if I include the f.c file with gcc main.c f.c -o f it works.
So, when compiling, should I include each C file that I used in my project, or am I missing something? Because adding each single file to gcc is very annoying.
When you have multiple source files that together make an executable, they must be each compiled and then linked together. This is done by specifying each source file when the compiler is invoked as you've discovered.
Note also that you can either do the compiling and linking in one step as you've done, or you can separate them as follows:
gcc -c main.c
gcc -c f.c
gcc -o f main.o f.o
Managing multiple source files and their dependencies is where using a makefile comes into play.
You need to understand there are three stages from c source code to run able binary. For etch and every file this stages must be followed except for header file or .h file.
First Stage : Source to assembly. gcc -S -o source.s source.c
Second Stage : assembly to Compiled Binary Object. Which can not be runned directly. gcc -c source.s -o source.o
Third Stage : In this stage we marge all the compiled binary to a single compiled binary where an input binary object holds an entry function int main().This the file which we can run on our operating system.gcc -o OutputFile source1.o source2.o source3.o ......
After this three stages we can run our program by ./OutputFile. You can avoid making assembly file and directly make object file.
Yeah you must include all the file for compilation in you project. You can use automation tools like automake or linux shell script for doing this job.

Step by step C compilation result in segfault

I'm trying to understand C compilation
Given this simple C code in main.c:
int main() {
int a;
a = 42;
return 0;
}
I performed the following operations:
cpp main.c main.i
/usr/lib/gcc/x86_64-linux-gnu/9/cc1 main.i -o main.s
as -o main.o main.s
ld -o main.exe main.o
When executing main.exe, I get a Segmentation Fault.
How can I get a good memory addressing in this example?
When I try the sequence of commands from your question on an x86_64 Ubuntu 19.10 system, I get a warning from ld:
ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
This is an indication that something is wrong.
The error means that the linker did not find a symbol _start and used a default address instead. When running your program it will try to execute code at this address which apparently is invalid.
An executable program compiled from C code doesn't contain only your code. The compiler instructs the linker to add C run-time library and startup code. The startup code is responsible for initialization and for calling your main function.
Run e.g.
gcc -v -o main.exe main.o
to see what other files get added to your program. On my system this shows a few files with names starting with crt which means "C runtime".
If you don't use gcc to link your program but use ld directly, you have to manually add all necessary object files in a similar way as the compiler would do automatically.

How to use asm procedure and take return value in C

i've got a gcc version 2.95.2 19991024 (release) toolchain and now i need to use an Assembly function that is in a file positioned in the same folder of the makefile.
I've tried tons of ways to put that file in my toolchain, with no luck.
Basically i declare that in ASM:
.globl util_MyFunc
util_MyFunc:
...
And in the main void of C file:
extern void util_MyFunc();
int main(void) {
util_MyFunc();
...
When i compile i got the error related to not recognized:
/cygdrive/c/MyDev/tmp/main.o(.text+0x8bc): undefined reference to `util_MyFunc'
make: *** [test.o] Error 1
Thanks!
EDIT:
i've tried to use following to generate the ".o" file from the asm file
C:\MyDev>gcc -c test.asm -o test.o
It results:
gcc: utils.asm: linker input file unused since linking not done
or:
C:\MyDev>gcc test.asm -o test.o
but...:
ld: cannot open crt0.o: No such file or directory
The canonical extension for assembly files that gcc expects is .s. You should use that (or assemble using as directly). Also possibly put the -o test.o before the input file name. Finally, you will need libc development files if you want to use libc. Otherwise use -nostdlib switch.
You should try: gcc -o test main.c utils.s

Compiling multiple C files with gcc

I have two files, main.o and modules.o, and I'm trying to compile them so that main.o can call functions in modules.o. I was explicitly told not to try #include module.o. I really don't know what I should be doing instead. I tried a few different versions of gcc (such as gcc -x c driver main.o modules.o), but nothing I get works: the compiler continuously returns
error: called object is not a function
The .o files are my source code files (I was instructed to put my source code in files with extension .o.) What do I do to compile this?
If you have your two source files, you can compile them into object files without linking, as so:
gcc main.c -o main.o -c
gcc module.c -o module.o -c
where the -c flag tells the compiler to stop after the compilation phase, without linking. Then, you can link your two object files as so:
gcc -o myprog main.o module.o
This is all perfectly normal behavior, you'll usually get your makefile to compile things separately and link them at the end, so you don't have to recompile every single source file every time you change one of them.
Talking about main.o "calling functions in" module.o is perfectly fine, but an .o file is not a source file, it's a compiled object file. If "put my source code in files with extension .o" actually meant "compile my source code into files with extension .o" then the situation would make a whole lot more sense.
You should define the functions that you want to call from modules.c into main.c into a header file, let us say modules.h, and include that header file in main.c. Once you have the header file, please compile both of the files together: gcc main.c modules.c -o output
Two additional notes. First, modules.o is an object file and it should not be included in a C source file. Second, we cannot have a C file have a .o extension. You should actually get an error when compiling a .o file. Something like:
$ cat t.o
int main() {
int x = 1;
return 0;
}
$
$ gcc t.o
ld: warning: in t.o, file is not of required architecture
Undefined symbols:
"_main", referenced from:
start in crt1.10.6.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
$
program: main.o
gcc -o main main.c anotherSource.c
This works for me.
You should be including .h files which are "headers". So if your main file is using modules then you should include module's header file.

Creating libraries in C/C++ - ld can't find my library

I'm trying to learn how to create a C/C++ library in a linux environment but I'm having a problem (probably a trivial one) that online tutorials had not helped to solve.
For definiteness let's say I have a foo.c file with the following code:
//file: foo.c
#include <stdio.h>
void hello(void)
{
printf("hello!\n");
}
a foo.h:
//file: foo.h
void hello(void);
and a program that uses the function hello() from foo.c, named prog.c:
//file: prog.c
#include "foo.h"
int main(void)
{
hello();
return 0;
}
The three files are all on the same directory. Then I compiled foo.c with:
gcc -fPIC -c foo.c
and got a foo.o file. Then I used ld to create the library file:
ld -G foo.o -o libfoo.so
But when I try to compile prog.c with:
gcc -o prog prog.c -lfoo
I got an error message:
/usr/bin/ld: cannot find -lfoo
collect2: ld returned 1 exit status
I'm convinced that this is some kind of trivial path problem, but I couldn't find the solution. So my question is really if this procedure above is wrong or if I have to put the libfoo.so file in a special path.
Another question is how this changes if I'm using g++ instead of gcc.
Thanks.
EDIT:
I know I can compile both prog.c and foo.c to prog.o and foo.o an then link them to make an executable. But in my original problem I want to compile foo.c in a way that I can distribute to people who will use my functions in their own programs.
ld doesn't search the current directory by default. If you want it to do this you need to use the -L command line option, so if your library is in the current directory you need to add -L. to the last gcc call. If the library is dynamically linked you also need to add the current directory to the environment variable LD_LIBRARY_PATH (I assume you're on linux).
Of course, if your library is in any other non-standard path you need to use that instead of the current directory.
Try
gcc -o prog prog.c -lfoo -L.
The -L switch adds its argument to the set of paths that ld looks in for library files. The syntax is identical for g++.

Resources