1

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 library z after file foo.o but before bar.o. If bar.o refers to functions in z, 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 with lib 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
Khoa Tran
  • 41
  • 1
  • 5
  • 4
    Unrelated, you need longjmp & setjmp like you need the plague. – Lundin May 09 '19 at 15:11
  • I don't know your exact situation, but mixing multiple standard libraries doesn't sound like the safest thing to do. – Thomas Jager May 09 '19 at 15:18
  • You need to put your 'stdio.c' into a library and put that before `-lc`. This will resolve those symbols from your `stdio.c` first. However, the linker option [`--wrap symbol`](ftp://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.html) is probably a better choice. Especially you can use scripts to get a list of wrapped symbols (via sed, on stdio.c source); especially is you mark the function with a macro and/or comment to denote they are special. This way your `--wrap` list is dynamic and functions can be added/deleted. – artless noise May 09 '19 at 16:19
  • Replacing machinery maybe difficult as you may have inter-dependancies between functions. Why not get the libc source and modify that and include it in the project. Especially if you static link, this is only a build time price but you solve many maintenance head aches. – artless noise May 09 '19 at 16:23
  • please add the command line for your link call to generate the .elf (or final binary, whatever it is). Chances are you're putting a .o into the link after the libraries have already been resolved, ending up in a multiple definition. – Russ Schultz May 09 '19 at 23:51
  • If you have newlib, there are cleaner mechanism to do what you want. See: [Syscalls in newlib](https://sourceware.org/newlib/libc.html#Syscalls) docs. – artless noise May 10 '19 at 14:33

2 Answers2

1

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.)

Elias
  • 913
  • 6
  • 22
  • 1
    This can work. The danger is that the libc may contain other libc function calls. For instance some DNS lookup which use a file to cache lookups. This DNS cache may use an esoteric libc function which you fail to wrap/implement. Your *toy* example won't exhibit this. I think this maybe the OPs issue. The best solution is probably `-wrap` with gcc/gnu ld. You won't get duplicate functions, just unimplemented which gives a clear path forward. – artless noise May 12 '19 at 17:20
0

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.

Babajan
  • 364
  • 3
  • 5
  • Maybe it is true that is *outside of the scope of the 'C' language*, but it is possible with some tools/setups. However, your suggestion to just wrap the function is fine and well supported on many tools, like gcc and gnu ld. Although it is better to change the name of the real function so that you don't need to ensure the main source is altered. This maybe very important if you use 3rd party source. – artless noise May 12 '19 at 17:14