Search code examples
gccmakefileclangldentry-point

Clang linker not recognising -e option but GCC linker does


I would like to use a Makefile to generate a binary that does unit tests for me. It takes all the object files of my program, as well a compiled tester object, and packages it all together. The issue is, I want to use a custom entry point inside the tester file instead of main.

So no problem, ld comes with a flag -e where I can specify said entry point. So inside of my Makefile I have written:

$(CC) $(ALL_CFLAGS) -Wl,-e$(TEST_ENTRY) $(OBJDIR)/$(TEST_SUITE:.c=.o) $(OBJECTS) -o $(BINDIR)/$(TARGET)-test

Taking care to note that I am doing all my linking with the gcc function so I have to pass my command to the linker with -Wl. This is where the problem begins:

Using gcc on Debian, this command works perfectly and my program runs as expected.

Using clang on MacOS, I am presented with the following error during compile time:

ld: unknown option: -etester
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [test] Error 1

The Makefile is putting the entry point (named tester) with the argument without any space. As far as I know, this should be perfectly acceptable? After all, gcc accepts it.

If I add a space, it will assume $(TEST_ENTRY) is an argument for the compiler instead. I can avoid this with quotation marks. So I also tried the following:

-Wl,"-e $(TEST_ENTRY)"

However I get the same error

ld: unknown option: -e tester

May I ask if anybody knows a solution that will allow clang to function correctly while not sabotaging the fact that it already works in gcc? Perhaps I am missing something here.


Solution

  • Function Name Mangling

    This seems related to the function name mangling of clang. To avoid user-defined function name duplicated with intrinsic function names in libc or Sysmte.A, compiler mangle user-defined function names. for c language, usually, a '_' is added as prefix.

    for example,

    int test(..)
    

    is mangled to

    _test in clang compilation procedure.

    Testing project:

    #include "stdio.h"
    
    int main(int argc, char const *argv[]) {
      printf("hello world\n");
      return 0;
    }
    
    int test(int argc, char const* argv[]){
      printf("hello test entry\n");
      return 0;
    }
    

    When compiled with clang helloworld.c -o helloworld,
    execution result:

    ╰─$ ./helloworld     
    hello world
    

    when compiled with clang helloworld.c -o helloworld -e_test,
    execution result:

    ╰─$ ./helloworld     
    hello test entry
    

    refer to https://en.wikipedia.org/wiki/Name_mangling for more details or reply to ask.