More GCC link time issues: undefined reference to main - c

I'm writing software for a Cortex-A8 processor and I have to write some ARM assembly code to access specific registers. I'm making use of the GNU compilers and related toolchains; these tools are installed on the processor board (Freescale i.MX515) with Ubuntu. I make a connection to it from my host PC (Windows) using WinSCP and the PuTTY terminal.
As usual I started with a simple C project having main.c and functions.s. I compile the main.c using GCC, assemble the functions.s using as and link the generated object files using once again GCC, but I get strange errors during this process.
An important finding -
Meanwhile, I found out that my assembly code may have some issues because when I individually assemble it using the command as -o functions.o functions.s and try running the generated functions.o using ./functions.o command, the Bash shell is failing to recognize this file as an executable (on pressing tab functions.o is not getting selected/PuTTY is not highlighting the file).
Can anyone suggest what's happening here? Are there any specific options I have to send, to GCC during the linking process? The errors I see are strange and beyond my understanding, I don't understand to what the GCC is referring.
I'm pasting here the contents of main.c, functions.s, the Makefile and the list of errors.
Help, please!!!
**Latest errors included after the makefile was edited as suggested here **
ubuntu#ubuntu-desktop:~/Documents/Project/Others/helloworld$ make
gcc -c -mcpu=cortex-a8 main.c
as -mcpu=cortex-a8 -o functions.o functions.s
gcc -o hello main.o functions.o
functions.o: In function `_start':
(.text+0x0): multiple definition of `_start'
/usr/lib/gcc/arm-linux-gnueabi/4.3.3/../../../crt1.o:init.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status
make: *** [hello] Error 1
main.c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
puts("!!!Hello World!!!"); /* prints !!!Hello World!!! */
return EXIT_SUCCESS;
}
functions.s
* Main program */
.equ STACK_TOP, 0x20000800
.text
.global _start
.syntax unified
_start:
.word STACK_TOP, start
.type start, function
start:
movs r0, #10
movs r1, #0
.end
Makefile
all: hello
hello: main.o functions.o
gcc hello -o main.o functions.o
-- hello was included here after suggested here by guys at Stack Overflow, but the problem still persists; I still get the same errors.
main.o: main.c
gcc -c -mcpu=cortex-a8 main.c
functions.o: functions.s
as -mcpu=cortex-a8 -o functions.o functions.s
Errors
ubuntu#ubuntu-desktop:~/Documents/Project/Others/helloworld$ make
gcc -c -mcpu=cortex-a8 main.c
as -mcpu=cortex-a8 -o functions.o functions.s
gcc -o main.o functions.o
functions.o: In function `_start':
(.text+0x0): multiple definition of `_start'
/usr/lib/gcc/arm-linux-gnueabi/4.3.3/../../../crt1.o:init.c:(.text+0x0): first defined here
/usr/lib/gcc/arm-linux-gnueabi/4.3.3/../../../crt1.o: In function `_start':
init.c:(.text+0x30): undefined reference to `main'
collect2: ld returned 1 exit status
make: *** [hello] Error 1

In the makefile:
hello: main.o functions.o
gcc -o main.o functions.o
should be:
hello: main.o functions.o
gcc -o hello main.o functions.o
As it stands, you are linking functions.o, but not main.o, and producing an output executable called main.o, which is overwriting your existing main.o.

Shouldn't
hello: main.o functions.o
gcc -o main.o functions.o
be
hello: main.o functions.o
gcc -o hello main.o functions.o

As Bigbohne suggests, gcc is trying to link in the standard runtime library. Try adding the -nostdlib option to your gcc call:
gcc -nostdlib -o hello main.o functions.o

I think that has something to do with the Runtime library the gcc is linking at the end.
And in this library there already is a "_start".
I think you have to compile without "std library". but than you wont have printf,getchar and all the other useful stuff.

Normally execution of a program compiled with gcc starts in the function called _start (in a startup file provided by gcc), which calls main.
If you are supplying your own _start, you should pass -nostdlib to gcc when linking. This disables all default startup files and all default libraries. You should therefore also explicitly provide any libraries you need such as libc and libgcc.
Your _start however does not call main, so it is unclear why you bother to provide main and the .c file at all.
gcc -o main.o functions.o is a mistake, it should be gcc -o main main.o functions.o, but this will not fix the problem described above.

Related

makefile: undefined reference to main

I am working on a simple project that generates 2 executable files, main and Server.
The program in Main.c makes use of code present in user_interface.c through the header file user_interface.h.
The Makefile I have written is as follows,
all: main user_interface.o Server
main: user_interface.o main.c
gcc main.c user_interface.o -o main
user_interface.o: user_interface.c user_interface.h
gcc user_interface.c -o user_interface.o
Server: Server.c
gcc Server.c -o Server
clean:
rm -rf main *.o Server
When I type make on the terminal, I get the following error:
gcc user_interface.c -o user_interface.o
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x24): undefined reference to `main'
collect2: error: ld returned 1 exit status
make: *** [Makefile:18: user_interface.o] Error 1
How do I navigate past this error?
Your rule for user_interface.o is wrong. You need to use the -c option to tell it that it's creating an object file rather than an executable, so it doesn't need a main() function.
all: main Server
main: user_interface.o main.o
gcc main.o user_interface.o -o main
main.o: main.c
gcc -c main.c
user_interface.o: user_interface.c
gcc -c user_interface.o
Server: Server.c
gcc Server.c -o Server
clean:
rm -rf main *.o Server
make actually has a built-in rule for compiling .c to .o, so you don't actually need those rules.
I think you're not using makefiles properly.
so a section of your makefile might look something like this:
core: WitchCraft NeuralServer AmoebaServer CDS NLPServer HollyServer
test: ENiX4NeuralCLI DataInjector NNTestServer ENiX4AmoebaCLI CLINLPTest
WitchCraft: ENiX_Net.o ENiX_IPC.o ENiX_SHM.o ENiX_Seq.o ENiX_Packet.o WitchCraft.o ENiX_Config.o ENiX_Disk.o ENiX_Binary.o
g++ -ggdb -O0 ENiX_Net.o ENiX_IPC.o ENiX_SHM.o ENiX_Seq.o ENiX_Packet.o WitchCraft.o ENiX_Config.o ENiX_Disk.o ENiX_Binary.o -o WitchCraft.bin -std=c++11 -lreadline
These things before the colon, are called targets. The can be called with:
make <target>
e.g.
make WitchCraft
So for the first line of your target you've got source files inside there for some reason and it looks like you're trying to compile user_interface.o as a binary, rather than an object, but you're not linking it to main.o.
So I suspect you want something like:
main: main.o user_interface.o
gcc main.o user_interface.o -o main
And what that should do is cause make to look for the source code for main.o (i.e. main.c) likewise for interface.o (i.e. interface.c) and then compile these into object files (i.e. .o files).
Then you'd link these object files into a binary, using gcc with the -o to specify the binary output file in this case, "main".
And you'd need to do something similar with the server.

How to use ld to link compiled .o files [duplicate]

I'm trying to get my head around how the linking process works when producing an executable. To do that I'm reading Ian Taylor's blog series about it, but a lot of it is beyond me at the moment - so I'd like to see how it works in practice.
At the moment I produce some object files and link them via gcc with:
gcc -m32 -o test.o -c test.c
gcc -m32 -o main.o -c main.c
gcc -m32 -o test main.o test.o
How do I replicate the gcc -m32 -o test main.o test.o stage using ld?
I've tried a very naive: ld -A i386 ./test.o ./main.o
But that returns me these errors:
ld: i386 architecture of input file `./test.o' is incompatible with i386:x86-64 output
ld: i386 architecture of input file `./main.o' is incompatible with i386:x86-64 output
ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
./test.o: In function `print_hello':
test.c:(.text+0xd): undefined reference to `_GLOBAL_OFFSET_TABLE_'
test.c:(.text+0x1e): undefined reference to `puts'
./main.o: In function `main':
main.c:(.text+0x15): undefined reference to `_GLOBAL_OFFSET_TABLE_
I'm most confused by _start and _GLOBAL_OFFSET_TABLE_ being missing - what additional info does gcc give to ld to add them?
Here are the files:
main.c
#include "test.h"
void main()
{
print_hello();
}
test.h
void print_hello();
test.c
#include <stdio.h>
void print_hello()
{
puts("Hello, world");
}
#sam : I am not the best people to answer your question because I am a beginner in compilation. I know how to compile programs but I do not really understand all the details (https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools)
So, I decided this year to try to understand how compilation works and I tried to do, more or less, the same things as you tried a few days ago. As nobody has answered, I am going to expose what I have done but I hope an expert will supplement my answer.
Short answer : It is recommended to not use ld directly but to use gcc directly instead. Nevertheless, it is, as you write, interesting to know how the linking process works. This command works on my computer :
ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o test test.o main.o /usr/lib/crt1.o /usr/lib/libc.so /usr/lib/crti.o /usr/lib/crtn.o
Very Long answer :
How did I find the command above ?
As n.m suggested, run gcc with -v option.
gcc -v -m32 -o test main.o test.o
... /usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 ... (many
options and parameters)....
If you run ld with these options and parameters (copy and paste), it should work.
Try your command with -m elf_i386 (cf. collect2 parameters)
ld -m elf_i386 test.o main.o
ld: warning: cannot find entry symbol _start; ....
Look for symbol _start in object files used in the full ld command.
readelf -s /usr/lib/crt1.o (or objdump -t)
Symbol table '.symtab' contains 18 entries: Num: Value Size
Type Bind Vis Ndx Name... 11: 00000000 0 FUNC
GLOBAL DEFAULT 2 _start
Add this object to your ld command :ld -m elf_i386 test.o main.o /usr/lib/crt1.o
... undefined reference to `__libc_csu_fini'...
Look for this new reference in object files. It is not so obvious to know which library/object files are used because of -L, -l options and some .so include other libraries. For example, cat /usr/lib/libc.so. But, ld with --trace option helps. Try this commandld --trace ... (collect2 parameters)At the end, you should findld -m elf_i386 -o test test.o main.o /usr/lib/crt1.o /usr/lib/libc_nonshared.a /lib/libc.so.6 /usr/lib/crti.oor shorter (cf. cat /usr/lib/libc.so) ld -m elf_i386 -o test test.o main.o /usr/lib/crt1.o /usr/lib/libc.so /usr/lib/crti.o
It compiles but it does not run (Try to run ./test). It needs the right -dynamic-linker option because it is a dynamically linked ELF executable. (cf collect2 parameters to find it) ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o test test.o main.o /usr/lib/crt1.o /usr/lib/libc.so /usr/lib/crti.o But, it does not run (Segmentation fault (core dumped)) because you need the epilogue of the _init and _fini functions (https://gcc.gnu.org/onlinedocs/gccint/Initialization.html). Add the ctrn.o object. ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o test test.o main.o /usr/lib/crt1.o /usr/lib/libc.so /usr/lib/crti.o /usr/lib/crtn.o./test
Hello, world

How to link a simple program in Windows with Mingw GCC

I have a simple "Hello World!" c program, named hello.c on my desktop:
#include <stdio.h>
int main() {
printf("Hello world!\n");
return 0;
}
I run the following commands.
I pre-process it with : cpp hello.c > hello.i
I compile it with : gcc -S hello.i
I assemble it with : as -o hello.o hello.s
All good so far. But, i'm unable to link it. I've tried, among other commands, these:
ld -o hello.exe hello.o
ld -o hello.exe hello.o -lgcc
ld -o hello.exe hello.o -nostdlib -lgcc
Nothing works. The link errors i get in every single case are :
hello.o:hello.c:(.text+0x9): undefined reference to `__main'
hello.o:hello.c:(.text+0x15): undefined reference to `puts'
How can i link this assembled program hello.o in order to finally produce the executable program hello.exe? What am i missing? [Using Windows 8.1, Mingw version 0.6.2.] Thanks in advance.
Even if your answers to clarification questions are not particularly useful:
Try something like
ld hello.o -lmsvcrt -entry=_main -subsystem=console -o hello.exe
If you want to see the linker command line the standard gcc uses, invoke gcc like so:
gcc test.c -o test -Wl,-v
The last lines output is what you should be using...
If you want to compile something rather than experimenting with tools, don't link it using the linker directly. Use gcc, which will call the linker for you with the right options:
Compile step:
gcc -c hello.c
Link step:
gcc -o hello.exe hello.o
Or all in one:
gcc -o hello.exe hello.c
You can also use a simple Makefile, then run make:
all: hello.exe

Am I writing this makefile correctly?

I am learning how to write C code in Linux and I am learning makefiles at a very beginner level.
I am having problems when making shared libraries.
The exercise is to make a simple function calculator C program with files:
main.c
add.c
subt.c
mult.c
div.c
The names of the files define the function they do.
The function in the file subt.c is in the static library:
libsubstatic.a
The function in the file mult.c is in the shared library:
libmultshared.so
For this program, I write the following makefile:
calc.exe: main.o add.o div.o libsubstatic.a libmultshared.so
gcc -o calc.exe main.o add.o div.o libsubstatic.a -Wl,-rpath,/home/ahmed/Desktop/labTask3 -lmultshared.so
main.o: main.c header.h
gcc -c main.c
add.o: add.c header.h
gcc -c add.c
libsubstatic.a: subt.o
ar cr libsubstatic.a subt.o
subt.o: subt.c header.h
gcc -c subt.c
libmultshared.so: mult.o
gcc -shared -fPIC -o libmultshared.so mult.o
mult.o: mult.c header.h
gcc -c -fPIC mult.c
div.o: div.c header.h
gcc -c div.c
The path where the code and makefile is placed:
/home/ahmed/Desktop/labTask3
I get the following message after I type "make" in the terminal:
gcc -o calc.exe main.o add.o div.o libsubstatic.a -Wl, -rpath, /home/ahmed/Desktop/labTask3 -lmultshared.so
gcc: error: unrecognized command line option ‘-rpath,’
make: *** [calc.exe] Error 1
What am I missing? Did I write this makefile correctly?
Please explain shared libraries, my concept might be faulty.
Please help.
Note that, I'm new to linux and I don't have much experience in makefiles.
EDIT: I removed the spaces as directed in the first answer. Now the terminal says:
gcc -o calc.exe main.o add.o div.o libsubstatic.a -Wl,-rpath,/home/ahmed/Desktop/labTask3 -lmultshared.so
/usr/bin/ld: cannot find -lmultshared.so
collect2: error: ld returned 1 exit status
make: *** [calc.exe] Error 1
Should I do something with the "-lmultshared.so"? What should I do?
-Wl, -rpath, /home/ahmed/Desktop/labTask3
Get rid of the spaces. This should all be one long argument.
-Wl,-rpath,/home/ahmed/Desktop/labTask3
See this excellent answer by #KerrekSB for a detailed explanation about passing arguments to the linker with -Wl.

Mixing programming of assembly and C in linux

There are only two files, main.c and kernel.asm, and I tried to make a program with them using NASM and GCC. contents are as follows:
main.c
#include <stdio.h>
void Print_String() {
printf("Hello World!\n");
}
kernle.asm
extern Print_String
[section .text]
global _start
_start:
call Print_String
Compile and Link:
nasm -f elf -o kernel.o kernel.asm
gcc -c -o main.o main.c
ld -s -lc -o final kernel.o main.o
Then I run the final file with the command: ./final, but the result is depressing:
bash: ./final: No such file or directory
However, the current directory does have the file final, for the command ls, it displays:
final kernel.asm kernel.o main.c main.o
So why it cannot find the file final? Is there anything wrong? Any help appreciated!
It is not that it cannot find it, per se. The error message is somewhat misleading. The dynamic linker cannot resolve its dependencies, and thus your program image is not loadable (and not executable)
The problem is that you are dynamically linking against libc without any other of the paraphernalia to make dynamic linking actually work. Thus you are left with a binary image that cannot be loaded.
You might find that it's easier to statically link against libc. This can be done as follows:
ld -Bstatic -o final kernel.o main.o -lc
Notice you have to move the '-lc' bit after the code module main.o which uses it.
If you try this, you'll get a whole bunch of unresolved symbols. That's because you will also need to link against libgcc and libgcc_eh.
The following got me fairly close (apologies, working on a 64-bit system here):
ld -L/usr/lib/gcc/x86_64-linux-gnu/4.4.3/32/ -melf_i386 -Bstatic -lc -o final kernel.o main.o -lc -lgcc -lgcc_eh
This failed for me with
/usr/lib/gcc/x86_64-linux-gnu/4.4.3/32//libgcc_eh.a(unwind-dw2-fde-glibc.o): In function `_Unwind_Find_FDE':
(.text+0x193b): undefined reference to `dl_iterate_phdr'
Which doesn't make much sense. You may have more luck linking 32-bit on a 32-bit system.
Update
Apologies for the ramble above. I had a think about this again, and, of course, it is possible to make dynamic linking work. The missing piece is to specify the dynamic linker:
In my case, this was:
ld -dynamic-linker /lib32/ld-linux.so.2 -melf_i386 -o final kernel.o main.o -lc
So for you the following should work:
ld -dynamic-linker /lib/ld-linux.so.2 -o final kernel.o main.o -lc
Update again
In response to markzar's comment - you have to make a syscall to cleanly exit. This has the effect of doing something similar to exit(0) in C:
mov eax,1 ; Syscall #1
mov ebx,0 ; Return code 0 = success
int 80H
Try this. First change kernel.asm as follows:
extern Print_String
[section .text]
global main
main:
call Print_String
Then use the following commands to create the executable (instead of the linker).
nasm -f elf -o kernel.o kernel.asm
gcc -c -o main.o main.c
gcc -o final kernel.o main.o
Very simple: there is no main() to call in the program... thus whatever you do, the C-program-startup machinery doesn't get a hold.

Resources