[LLVMdev] Unexpected behaviour of the LLVM gold plugin with --allow-multiple-definition

Milan Lenčo xlenco at fi.muni.cz
Wed Oct 16 13:36:43 PDT 2013


Dear LLVM development team,

working with the LLVM gold plugin, I have encountered an unexpected 
behaviour when the option --allow-multiple-definition (or -z muldefs) is 
specified for the linker.

Let's suppose the following scenario with four simple source files:

----- main.c ------
#include "unit.h"

int main() {
     only_in_unit1();
     only_in_unit2();
     return get_unit_id();
}

----- unit.h ------

#ifndef _UNIT
#define _UNIT 1

int get_unit_id( void );
void only_in_unit1( void );
void only_in_unit2( void );

#endif

----- unit1.c ------

#include "unit.h"

int get_unit_id( void ) {
     return 1;
}

void only_in_unit1( void ) {}

----- unit2.c ------

#include "unit.h"

int get_unit_id( void ) {
     return 2;
}

void only_in_unit2( void ) {}

-----------------------

Now when I compile the sources with clang and link it with GNU gold, for 
both ordering of unit1.c and unit2.c in the input arguments, everything 
seems to work fine:

$ clang -Wl,-v,-allow-multiple-definition, main.c unit1.c unit2.c -o ldtest
GNU gold (GNU Binutils for Ubuntu 2.22) 1.11
$ nm ./ldtest
...
0000000000400590 T get_unit_id
0000000000400570 T main
00000000004005c0 T only_in_unit1
00000000004005a0 T only_in_unit2
...
$  ./ldtest; echo $?
1

$ clang -Wl,-v,-allow-multiple-definition, main.c unit2.c unit1.c -o ldtest
GNU gold (GNU Binutils for Ubuntu 2.22) 1.11
$ nm ./ldtest
...
0000000000400590 T get_unit_id
0000000000400570 T main
00000000004005c0 T only_in_unit1
00000000004005a0 T only_in_unit2
...
$ ./ldtest; echo $?
2

In the first case linker correctly choosed get_unit_id from unit1.o, in 
the second case from unit2.o. But what is important here, is that in 
both cases only_in_unit1 and only_in_unit2 are defined as it should be.
However, when working with LLVM, the outcome is different:

$ clang -c -emit-llvm  main.c
$ clang -c -emit-llvm  unit1.c
$ clang -c -emit-llvm  unit2.c
$ ld-new --plugin /usr/local/lib/LLVMgold.so --allow-multiple-definition 
-plugin-opt emit-llvm main.o unit1.o unit2.o -o ldtest.bc
$ llvm-nm ldtest.bc
          t get_unit_id
          t main
          t only_in_unit1
          U only_in_unit2
$ llvm-dis ldtest.bc -o ldtest.llvm; cat ldtest.llvm
...
; Function Attrs: nounwind uwtable
define internal i32 @main() #0 {
entry:
   %retval = alloca i32, align 4
   store i32 0, i32* %retval
   call void @only_in_unit1()
   call void @only_in_unit2()
   %call = call i32 @get_unit_id()
   ret i32 %call
}

declare void @only_in_unit2() #1

; Function Attrs: nounwind uwtable
define internal i32 @get_unit_id() #0 {
entry:
   ret i32 1
}

; Function Attrs: nounwind uwtable
define internal void @only_in_unit1() #0 {
entry:
   ret void
}
...

And similary for the other ordering of unit1 and unit2.

As it can be seen from the output, get_unit_id is chosen correctly from 
the first unit*.c file specified in the input arguments.
However, the symbol only_in_unitX, where unitX is the second specified 
unit file, is undefined. In general, it seems that whenever a file has a 
symbol which was overridden, all symbols from the file are ignored and 
not linked into the output file.

Is this an intended behaviour or I am misusing the commands and/or options?
Please let me now if there is any workaround (e.g. script for the GNU 
gold linker) so that I can get the same outcome as in the case without 
--emit-llvm.

Kind regards,

Milan Lenčo
Parallel and Distributed Systems Laboratory
Faculty of Informatics
Brno, Czech Republic






More information about the llvm-dev mailing list