Trying to figure out a way to link object files that I've built with arm-none-eabi-ld
Here's a directory structure for my build
Application
- main.c
- start.s
- linker.ld
build
- main.o
- start.o
I just typed this command to make an executable.
Harrys-MacBook-Pro:FreeRTOS-CortexA15 kwooly$ arm-none-eabi-ld -T Application/linker.ld -lc build/start.o build/main.o -o kernel.elf
and I got following error.
arm-none-eabi-ld: cannot find start.o
Is there any way to tell ld that the start.o is in the build directory?
I've tried -L option but wasn't really good.
build/start.o: In function _start':
(.text+0x0): multiple definition of_start'
build/start.o:(.text+0x0): first defined here
Harrys-MacBook-Pro:FreeRTOS-CortexA15 kwooly$
This question is quite similar with this one,arm-none-eabi-ld: cannot find -lc. Therefore, you could try to reorder it, such as $arm-none-eabi-ld build/start.o build/main.o -T Application/linker.ld -lc -o kernel.elf.
Related
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
My teacher is not the best at explain C so I'm having a bit of trouble understanding the connection of makefiles. I have already added the code for complex.c, complex.h, and main.c. I'm just having trouble compiling it all using the make command. I followed the example on the powerpoint he handed up and I don't understand why its failing to get to complex.
makefile
complex: main.o complex.o
gcc -o complex main.o complex.o
main.o: main.c complex.h
gcc -c main.c -lm
complex.o: complex.c complex.h
gcc -c complex.c -lm
clean:
rm*.o complex
ls
main.o
main.o: complex.h
gcc -c main.c
complex.o
complex.o: complex.h
gcc -c complex.c
Error
mason% make
gcc -o complex main.o complex.o
ld: fatal: file main.o: unknown file type
ld: fatal: file processing errors. No output written to complex
collect2: error: ld returned 1 exit status
*** Error code 1
make: Fatal error: Command failed for target `complex'
It looks like you have put Makefile fragments inside main.o and complex.o. These should be generated by the compiler, not by you.
Delete these files, and make again.
Additionally, your make clean rule is missing a space.
clean:
rm *.o complex
ls
One more thing. No need for -lm in the compile lines.
main.o: main.c complex.h
gcc -c main.c
complex.o: complex.c complex.h
gcc -c complex.c
You should add -lm at the linking phase.
complex: main.o complex.o
gcc -o complex main.o complex.o -lm
The "Makefile" defines and controls the build dependencies.
For example, you can't build the main executable binary without first building the binary object/module files that go with it. In this case, those are main.o and complex.o.
Generally any object file you need also needs a rule (though some rules can use "wildcards" to build more).
This is all rather academic. Best to take errors at their word and try to disprove them (this one basically says that main.o exists and is incorrect). In this case the hypothesis that main.o exists is supported by the fact that it didn't compile when you ran the make command.
Until you learn more you could invoke "make" using "targets". Like: make clean and make complex. It might help bring clarity.
A lot of makefiles put an "all" target to sort of reset the build. That then depends on "clean" and the executable and library targets. Like:
all: clean complex
So then you "make all" to clean and build.
A good tutorial is here. Mrbook Makefile Tutorial
I'm new to C programming, and I'm trying to compile this Simple training example with GCC on Ubuntu 12.10.
Looks like fann.h should not be included (as stated on the file itself), so I included fixedfann.h instead.
First attempt (without include, just to see what the compiler will ask for):
$ gcc main.c -o output
/tmp/cckKyM92.o: In function `main':
main.c:(.text+0x62): undefined reference to `fann_create_standard'
main.c:(.text+0x7a): undefined reference to `fann_set_activation_function_hidden'
main.c:(.text+0x8e): undefined reference to `fann_set_activation_function_output'
main.c:(.text+0xba): undefined reference to `fann_train_on_file'
main.c:(.text+0xce): undefined reference to `fann_save'
main.c:(.text+0xda): undefined reference to `fann_destroy'
collect2: ld returned 1 exit status
fann_create_standard is on fann.h and fann.c. As fann.h is included by fixedfann.h, and fann.h should not be included directly, I believe I have to compile fann.c and fixedfann.c, and link then (tell me if I'm doing any mistake, I'm still not familiar with this "linking" stuff).
So I did:
$ gcc fann/fixedfann.c -o fann/fixedfann.o
fann/fixedfann.c:22:20: fatal error: config.h: No such file or directory
compilation terminated.
and then I did:
$ gcc fann/fixedfann.c -o fann/fixedfann.o -include fann/include/config.h
fann/fixedfann.c:22:20: fatal error: config.h: No such file or directory
compilation terminated.
Now, why it's not finding the config.h file here?
--update
Thanks #JonathanLeffler, I could make some steps here. But now I'm stuck at:
$ gcc fann/fixedfann.c -o fann/fixedfann.o -I./fann/include/ -lm
/usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
collect2: ld returned 1 exit status
and, with grep, I could not find any reference to main on the fann folder... Also no function _start, and I don't know who is linking this crt1.o... Any idea what's wrong here?
--update2
Ok, I got the .o files using Harmeet's Makefile, now I'm trying to link everything.
I created the main.o with gcc -c main.c, and I tried:
gcc -o output main.o fann/fixedfann.o -lm
(-lm for the libmath, that is needed) and I got:
main.c:(.text+0xba): undefined reference to `fann_train_on_file'
This fann_train_on_file is on fann_train_data.c, so I tried:
gcc -o output main.o fann/fixedfann.o fann/fann_train_data.o -lm
but I got lots of multiple definition of... errors... :/
Looks like fann_train_data.o is already included/linked, but if so, why it's not finding fann_train_on_file?
--update3
I'm still really stuck here... Any idea of which (if any) of this two lines should work?:
gcc -o output main.o hello.o fann/fixedfann.o fann/fann_train_data.o -lm
or
gcc -o output main.o hello.o fann/fixedfann.o -lm
--update for Harmeet
The output was:
$ make
gcc -L./fann -lfann main.o -o main
main.o: In function `main':
main.c:(.text+0x62): undefined reference to `fann_create_standard'
main.c:(.text+0x7a): undefined reference to `fann_set_activation_function_hidden'
main.c:(.text+0x8e): undefined reference to `fann_set_activation_function_output'
main.c:(.text+0xba): undefined reference to `fann_train_on_file'
main.c:(.text+0xce): undefined reference to `fann_save'
main.c:(.text+0xda): undefined reference to `fann_destroy'
collect2: ld returned 1 exit status
make: *** [main] Error 1
You can use ar to make a static library and work with that.
Create a Makefile under your hello-fann-3/fann/ folder with the following contents -
SOURCES = $(wildcard *.c)
OBJECTS = $(SOURCES:.c=.o)
CFLAGS = -c -Iinclude
all: libfann.a
libfann.a: $(OBJECTS)
ar rcs $# $^
%.o: %.c
gcc $(CFLAGS) $^
Then use the make command in hello-fann-3/fann/ to build the static library. The above Makefile will generate libfann.a that you can link to your program.
Create a Makefile under your hello-fann-3/ folder with the following contents -
SOURCES = $(wildcard *.c)
OBJECTS = $(SOURCES:.c=.o)
CFLAGS = -c -I./fann/include
LFLAGS = -L./fann -lfann
main: $(OBJECTS)
gcc $(LFLAGS) $^ -o $#
%.o: %.c
gcc $(CFLAGS) $^
Then use the make command in hello-fann-3/ to build the main program.
In your main.c, you must include fan.h like -
#include "fann.h"
If you do not understand the Makefile, you can read about it here -
http://www.gnu.org/software/make/manual/html_node/index.html
You just need to link the fann library.
If you compile manually do this
gcc main.c -lfann -lm -o main
then simply run it like
./main
If you are on Ubuntu and you faced the following error
./main: error while loading shared libraries: libfann.so.2: cannot open shared object file: No such file or directory
Then run
sudo ldconfig
If you are using NetBeans, then simply Right click on your project -> Properties -> Build -> Linker,
then in the Libraries section click on the browse button [...] then in the new window click on Add Library...
Then add fann library (for example my fann library path is: /usr/local/lib/libfann.a) and click Ok
A fellow helped me, and we came to this line that compiled everything, and make the executable:
$ gcc fann/fann.c fann/fann_io.c fann/fann_train.c fann/fann_train_data.c fann/fann_error.c fann/fann_cascade.c main.c -Ifann/include -lm
And this is the answer.
That said, this is exactly what fixedfann.c is doing (include all this .c files). But if I try:
$ gcc fann/fixedfann.c main.c -Ifann/include -lm
..I get:
undefined reference to `fann_train_on_file'
This fann_train_on_file is on fann_train_data.c, which is included by fixedfann.c, so why it is undefined? I don't know... :/
--update
I realized that:
$ gcc fann/fixedfann.c main.c -Ifann/include -lm
will work if I comment the headers on fixedfann.c:
//#include "config.h"
//#include "fixedfann.h"
#include "fann.c"
#include "fann_io.c"
#include "fann_train.c"
#include "fann_train_data.c"
#include "fann_error.c"
#include "fann_cascade.c"
I am trying to build a library (Tesseract OCR) for Android. It seems to compile just fine, and I get a bunch of static libraries, but it fails during the linking phase.
The command is:
libtool: link: /opt/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86/bin/arm-linux-androideabi-g++ -fPIC -DPIC -shared -nostdlib /opt/android-ndk-r8c/platforms/android-8/arch-arm/usr/lib/crtbegin_so.o -Wl,--whole-archive ./.libs/libtesseract_api.a ../ccmain/.libs/libtesseract_main.a ../cube/.libs/libtesseract_cube.a ../neural_networks/runtime/.libs/libtesseract_neural.a ../textord/.libs/libtesseract_textord.a ../wordrec/.libs/libtesseract_wordrec.a ../classify/.libs/libtesseract_classify.a ../dict/.libs/libtesseract_dict.a ../ccstruct/.libs/libtesseract_ccstruct.a ../image/.libs/libtesseract_image.a ../cutil/.libs/libtesseract_cutil.a ../viewer/.libs/libtesseract_viewer.a ../ccutil/.libs/libtesseract_ccutil.a -Wl,--no-whole-archive -Wl,-rpath -Wl,/Users/xxx/dev/libs/leptonica/current/android-arm/release/lib -Wl,-rpath -Wl,/Users/xxx/dev/libs/leptonica/current/android-arm/release/lib -L./ -L../ -L../api -L../ccutil -L../viewer -L../cutil -L../image -L../ccstruct -L../dict -L../classify -L../wordrec -L../neural_networks/runtime -L../textord -L../cube -L../ccmain -L/opt/android-ndk-r8c/platforms/android-8/arch-arm/usr/lib -L/Users/xxx/dev/libs/leptonica/current/android-arm/release/lib /Users/xxx/dev/libs/leptonica/current/android-arm/release/lib/liblept.so -lz -L/opt/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/armv7-a -L/opt/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86/bin/../lib/gcc/arm-linux-androideabi/4.6 -L/opt/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86/bin/../lib/gcc -L/opt/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/lib -lstdc++ -lm -lc -ldl -lgcc /opt/android-ndk-r8c/platforms/android-8/arch-arm/usr/lib/crtend_so.o -Os -march=armv7-a --sysroot /opt/android-ndk-r8c/platforms/android-8/arch-arm -mfloat-abi=softfp -mfpu=vfpv3-d16 -marm -Wl,-rpath-link=/opt/android-ndk-r8c/platforms/android-8/arch-arm/usr/lib -Wl,-soname -Wl,libtesseract.so.3 -o .libs/libtesseract.so.3.0.1
And the output looks like:
/opt/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: error: ./.libs/libtesseract_api.a: member at 8 is not an ELF object
/opt/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: error: ./.libs/libtesseract_api.a: member at 96 is not an ELF object
/opt/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: error: ./.libs/libtesseract_api.a: member at 104400 is not an ELF object`
...
As far as I can tell, libtesseract_api.a and related files are valid. Any idea what's happening here? This isn't an error I've seen before.
Check if you have the right archive type by nm
.../arm-linux-androideabi-nm .libs/libtesseract_api.a
You should use the right format.
After adding the following to PATH, it link success :
$ANDROID_NDK/toolchain/bin
Here's my Makefile:
DIR=..
ARG=$(QUERY_STRING)
MAIN=main
SRC_DIR=$(DIR)/src
BIN_DIR=$(DIR)/bin
INC_DIR=$(DIR)/inc
LIB_DIR=$(DIR)/lib
LIBS=markdown
all: $(MAIN) exec
$(MAIN): $(MAIN).o
$(LD) $^ -L $(LIB_DIR) -l $(LIBS) -o $(BIN_DIR)/$#
$(MAIN).o: $(SRC_DIR)/$(MAIN).c
$(CC) $^ -I $(INC_DIR) -o $#
exec:
$(BIN_DIR)/$(MAIN) $(ARG)
clean:
rm -f *.o core.* $(BIN)/$(MAIN)
It's clearly defined how my project is organized, so I will not explain it. It does compile without any problems, but on binary execution $(BIN_DIR)/$(MAIN) the following error appears:
../bin/main: error while loading shared libraries: rintf: cannot open shared object file: No such file or directory
make: *** [exec] Error 127
What library does rintf belong? I tried to link -lc too, but that doesn't solves the problem.
Is there something wrong with my Makefile? Or should I link something extra to $(MAIN)?
Thanks in advance for your responses.
You should essentially never link a program by invoking ld directly; always use your compiler to do the linking. It passes all sorts of extra arguments to ld to make things work. Replace the $(LD) with $(CC). Do that regardless of whether it actually fixes your problem or not.
'Tis odd that you are not getting the name of the shared object specified in the error message.
This manual page for rintf() indicates that it is declared in <math.h>; most likely, you need to add the maths library to the link line: -lm.
I would rewrite some of your makefile:
LIB1 = -lmarkdown
LIB2 = -lm
LIBS = $(LIB1) $(LIB2)
LDFLAGS = -L $(LIB_DIR)
...
$(MAIN): $(MAIN).o
$(CC) $^ $(LDFLAGS) $(LIBS) -o $(BIN_DIR)/$#
Usually, this error appears when the linker is not able to find the needed shared object (.so file).I am assuming Linux platform.
In Linux OS, you can search for the file using: find, or locate. If you can find the .so file, try to update the linker cache using ldconfig. If it did not work, check the linker configuration files under /etc/ld.conf.d/ to see if the library path is included. If you changed the configuration, don't forget to update the cache again!