Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LLVM IR types being collapsed wrongly when linking (C++ API)

Straight to the point -- I'm trying to link two (or more) llvm modules together, and I'm facing a certain odd error from LLVM.

I don't want to post too much code, so I'll use a bunch of pseudo here.

I have 3 modules, let's say A, B, and C. A is the main module; I initialise llvm::Linker with it. B and C are secondary modules; I call linker.linkInModule(B and C).

All 3 modules have, among other things, these two types defined:

%String = type { i8*, i64 }
%Character = type { i8*, i64 }

Note that they have the same member types. Furthermore, a function foo is defined as such (in module B):

define i1 @_ZN9Character7hasDataEv(%Character*) { }

This function is declared in modules A and C. Now, all seems well and good -- this function is called from both modules A and C, and the IR looks normal, like so:

%21 = call i1 @_ZN9Character7hasDataEv(%Character* %4)

Here comes the problem: when all 3 modules are linked together, something happens to these types:

  1. They lose their name, becoming %2 (%String) and %3 (%Character).
  2. They appear to be merged together.

Strangely, while this transformation occurs in both modules A and C, the bug only occurs in C -- note that A is the so-called "main" module.

The function definition of the linked file is now

define i1 @_ZN9Character7hasDataEv(%2*)

Note how %Character, or %3, got turned into %2. Furthermore, at the callsite, in what is presumably an attempt to un-merge the types, I get this:

%10 = call i1 bitcast (i1 (%2*)* @_ZN9Character7hasDataEv to i1 (%3*)*)(%2* %2)

Curiously, although the function was casted from i1 (%2*) to %3 (%2*), the argument passed (arg. 1) is still of type %2. What's going on?

Note that in module A, whatever is going on is done properly, and there is no error. This happens for a number of functions, but only in module C.

I've tried reproducing it by copy-pasting these to .ll files and calling llvm-link followed by llvm-dis, but 1. the types are not merged, and 2. there is no such bug.

Thanks...?

like image 916
zhiayang Avatar asked Nov 09 '22 13:11

zhiayang


1 Answers

Okay, turns out that, after some poking around in the llvm IRC channel, llvm::Linker was meant to be used with an empty llvm::Module as the starting module.

Also, in my use-case I am reusing the same llvm::Type (the actual thing in memory) across different modules that I link together. They said it wasn't illegal, but that it was never tested, so... ¯\_(ツ)_/¯

So anyway, the problem was fixed by starting with an empty module to pass to the linker.

like image 115
zhiayang Avatar answered Nov 14 '22 21:11

zhiayang