[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