5

Recently started C coding on Linux and ran into a 'multiple definition' error (sources A.c and B.c below)

gcc -Wall A.o B.o -o C

/usr/bin/ld: B.o: in function "Hello":
B.c:(.text+0x0): multiple definition of `Hello'; A.o:A.c:(.text+0x0): first defined here

Searching thru S.O, it was suggested to use this linker command line option

--allow-multiple-definition (-z muldefs)
Normally when a symbol is defined multiple times, the linker will report a fatal error.
These options allow multiple definitions and the first definition will be used.

Running this command bypassed the error message

gcc -Wall -Wl,--allow-multiple-definition A.o B.o -o C

It seemed peace was restored, however, it output

./C

Hello A
Hello A
World B

I was expecting this output below and "assumed" the linker would smoothly resolve any symbol conflicts, but at least keep the existing code functionality

Hello A
Hello B
World B

However, the resulting C ELF binary was modified as follows by examining the assembly output from objdump -S -M intel C

  • Removed the duplicate Hello() in B.c
  • Re-pointed any calls to Hello() in A.c

Questions

  1. Is renaming the symbol Hello() the only correct solution?
  2. Is it bad practice to use --allow-multiple-definition option?
  3. If possible, should the linker be more sentient about intended code functionality by restricting a functions visibility i.e., understand that Hello() is a duplicate symbol in B.o and calling it from World() should be confined to B.o instead of looking into A.o?



gcc -Wall -c A.c

#include <stdio.h> void Hello(void) { printf("Hello A\n"); } int main() { Hello(); World(); return 0; } 

gcc -Wall -c B.c

#include <stdio.h> void Hello(void) { printf("Hello B\n"); } void World(void) { Hello(); printf("World B\n"); } 

EDITED

Based upon the comments/answers, adding the static keyword worked nicely

static void Hello(void) { printf("Hello B\n"); } 

No need to use that command line option now

gcc -Wall A.o B.o -o C

Hello A
Hello B
World B

The real impetus for the question is that we build a UASM assembly object file, and given the tip about the C static keyword, at least I can now research what's available in UASM to make these functions PRIVATE to the object.

UPDATE

For UASM, was able to make the function scope limited to the object file by adding

PROC PRIVATE FRAME 

Thanks!

5
  • 4
    To restore peace properly, add static to the definitions of Hello. Commented Sep 25, 2021 at 14:18
  • I wonder how the addition of the --allow-multiple-definition option ever got through code review... Commented Sep 25, 2021 at 14:27
  • If you have multiple definitions of a function with external linkage, the behaviour of your program is undefined. It's in section 6.9 of the C standard (phrased in terms of "there shall be a single definition"). Commented Sep 25, 2021 at 14:48
  • I don't understand the purpose of this question. You have written a C program which is obviously incorrect, and you are then trying to use all sorts of obscure compiler-specific tricks to make it build anyway. But why? Are you aware that your program is incorrect? If so, what is to be accomplished by making it build? Commented Sep 26, 2021 at 1:50
  • Recently a co-worker linked a large object (say B.o) along with another object (say A.o) but ran into the multiple definiton errors. I suggested using --allow-multiple-definition to allow the project to build. Re-thinking later, I wondered what exactly did that option do and was it bad advice? I constructed this contrived question to dig into the internals. The option has bad outcomes. The suggested fix was to create a "static" function whose scope is limited to its object file. This worked nicely. UASM assembly objects can possibly be linked in too and resolved by PROC PRIVATE FRAME. Commented Sep 26, 2021 at 13:18

1 Answer 1

5
  1. Name change is best but you could also make them static (to limit access to the file they are in) or change the signature just a little bit.

  2. Yes. Unbelievably bad ! In the real world you're expecting Hello() to do something, but now you're letting the compiler decide which version of Hello() to use - might be right. Might be wrong. It's madness to even have this option (IMHO).

  3. You can do that by making them static.

This is all a bit academic. Why do you think having 2 global scope functions called Hello() is a good idea in the first place ?

Sign up to request clarification or add additional context in comments.

1 Comment

One plausible reason for this option is when your software includes a third-party header with inline int f(){return 0;} and you want to compile a debug version with no inlining.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.