Milan Lenčo
2013-Oct-16 20:36 UTC
[LLVMdev] Unexpected behaviour of the LLVM gold plugin with --allow-multiple-definition
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
Rafael Espíndola
2013-Oct-18 19:39 UTC
[LLVMdev] Unexpected behaviour of the LLVM gold plugin with --allow-multiple-definition
> 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.Hi Milan, What was going on is that the gold plugin was ignoring errors from the IR linker and continuing with a broken module. I have fixed that in r192996 and gold should now report an error.> 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.To implement this we need two things: * The ir linker itself needs to get a --allow-multiple-definition option.That is, llvm-link of unit1 and unit2 should work if given that option. * We need to extend the gold api so that the plugin (and therefore llvm) knows that --allow-multiple-definition is in effect. Cheers, Rafael