Reputation: 41
I am working on an embedded system which has its own library (e.g. libc_alt ) implementing some functions from standard libc (fopen, fclose, fread, fseek, ftell) but not all ( I need memset, memcpy, longjmp, setjmp, etc. from the standard libc ). When I try to give both libraries to the compiler
Providing libc_alt
# makefile.mk
(SRC_C += \
$(COMP_PATH_libc_alt)/stdio.c \
)
Providing standard library
STD_LIBS += -lc -lgcc
During the Linker step, the compiler (arm-eabi-gcc) rightfully complains about multiple definitions of fclose(). My question is, Is it possible to instruct the compiler to exclude the standard libc definitions fclose() and use my definition written in $(COMP_PATH_libc_alt)/stdio.c ?
Or, how do I instruct the compiler to use my stdio.c first, then use the standard libc's stdio.c while ignoring repeated function definitions?
e.g. after it found fopen() definition in $(COMP_PATH_libc_alt)/stdio.c ; it will ignore fopen() inside the standard libc. That way I can use both libc_alt fopen() and the standard libc memcpy(), memset()
UPDATE: Thank you all for your answers. @artless_noise I did place my stdio.c before -lc
. Regarding using --wrap symbol
, if I understand correctly, reference to fclose()
will change to __wrap_fclose()
, and I need to change the name of my fclose()
in my stdio.c to __wrap__fclose()
; unfortunately, modifying "my" stdio.c is out of question.
Actually, the strangest thing is that, since I place my stdio.c before -lc, LinaroGCC arm-eabi-gcc was able to choose my definition for fopen(), fseek(), ftell(), fread()
(nice). But it gives multiple definition
error for fclose()
According to https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Link-Options.html; on ld -l
; the linker should have ignored repeated symbol in -lc
which come after my libc_alt.a
. And it did, with one exception fclose()
, and I dont know why?
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus,
foo.o -lz bar.o
searches libraryz
after file foo.o but before bar.o. If bar.o refers to functions inz
, those functions may not be loaded. The linker searches a standard list of directories for the library, which is actually a file named liblibrary.a. The linker then uses this file as if it had been specified precisely by name. The directories searched include several standard system directories plus any that you specify with -L. Normally the files found this way are library files—archive files whose members are object files. The linker handles an archive file by scanning through it for members which define symbols that have so far been referenced but not defined. But if the file that is found is an ordinary object file, it is linked in the usual fashion. The only difference between using an -l option and specifying a file name is that -l surrounds library withlib
and.a
and searches several directories.
How I call the linker (libc_alt.a
contain "my" stdio.o)
gcc-linaro-7.1.1-2017.08-x86_64_arm-eabi/bin/arm-eabi-gcc
-Xlinker --wrap=fclose -nostdlib -Xlinker --gc-sections
-Xlinker --fatal-warnings -Xlinker --no-wchar-size-warning
-Xlinker --no-enum-size-warning -Xlinker --build-id=none -T
/home/alice/Tools/Out/trusted_application.ld -Xlinker -pie -o
/home/alice/Out/Bin/taMbedTLS.axf /home/alice/Locals/Code/aes.o
/home/alice/Locals/Code/sha1.o /home/alice/libraries/libc_alt.a -lc -lgcc
Using nm
, contents of my libc_alt.a
stdio.o:
U __aeabi_uidiv
000000d0 t $d
0000004c t $d
00000030 t $d
00000010 N $d
00000001 T fclose
00000001 T fopen
00000001 T fread
00000001 T fseek
00000001 T ftell
U memset
U __stack_chk_fail
U __stack_chk_guard
U strchr
U strcmp
U strlen
stdlib.o:
Using nm
, contents of Linaro LinaroGCC arm-eabi-gcc libc.a
lib_a-fclose.o:
00000000 t $a
00000110 t $d
00000010 N $d
00000100 T fclose
00000000 T _fclose_r
U _free_r
U _impure_ptr
U __sflush_r
U __sfp_lock_acquire
U __sfp_lock_release
U __sinit
lib_a-fopen.o:
00000000 t $a
000000fc t $a
000000e8 t $d
00000110 t $d
00000010 N $d
000000fc T fopen
00000000 T _fopen_r
U _fseek_r
U _impure_ptr
U _open_r
U __sclose
U __sflags
U __sfp
U __sfp_lock_acquire
U __sfp_lock_release
U __sread
U __sseek
U __swrite
Upvotes: 1
Views: 4011
Reputation: 382
You cannot do that in c language.
What best you can do is write your functions with different names.
For example instead of fopen implement fileopen function in your code and use it wherever you need.
Upvotes: 0
Reputation: 923
You can do it. You do not need to instruct the compiler/linker in any special way, just link your own stuff and it will be used.
Here is a toy example showing how you can get your own fread() implementation.
Create the file fopen_test.c
like this:
#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode) {
printf("My own fopen implementation, just returning NULL.\n");
return NULL;
}
Now that can be compiled like this:
gcc -c fopen_test.c
which generates the object file fopen_test.o
.
If you then have the following main program in fopen_test_main.c
:
#include <stdio.h>
int main() {
printf("Calling fopen()\n");
FILE* f = fopen("file.txt", "rb");
printf("After fopen()\n");
return 0;
}
then you can see how that program behaves differently depending on whether you link with the fopen_test.o
object file.
First, try it using standard fopen() implementation:
$ gcc fopen_test_main.c
$ ./a.out
which gives the following output:
Calling fopen()
After fopen()
Now, try the same thing but linking with the object file containing the special fopen implementation:
$ gcc fopen_test_main.c fopen_test.o
$ ./a.out
which gives the following:
Calling fopen()
My own fopen implementation, just returning NULL.
After fopen()
So, now the fopen() implementation in fopen_test.c
is used instead of the standard implementation.
(I don't know why you got complaints about "multiple definitions", would need more details about what you did to figure that out.)
Upvotes: 1