storage class 0 symbol is generated for a double constant in COFF-x86-64 object file


I am using the llvm codegen facility (version 7.0.1) to translate LLVM IR for different platforms. I have this error particularly in win64 platform. In my IR code I have such code snippet:

%50 = call i8* @my_function(i8* %48, double 2.000000e+00, double 2.000000e+00)

declare dllimport i8* @my_function(i8*, double, double)

By passing it to llc.exe, I find following symbol is declared in object file’s symbol table.

[10](sec 5)(fl 0x00)(ty 0)(scl 0) (nx 0) 0x00000000 __real@4000000000000000

which has storage class 0, and it will lead to an error when I try to link it with the rest of objects.

obj1.obj: Unrecognized storage class 0 for .rdata symbol `__real@4000000000000000’.

As comparison, I compile an equivalent c file (to my llvm asm file) using clang-7.0 and emit the llvm from there. For this particular line, I see no difference in terms of syntax, except clang generates bunch of function attributes to the function declaration. I pass the clang generated llvm asm to llc and find the output object file also has one symbol has the same name, but the storage class is set to 2.

[10](sec 5)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 __real@4000000000000000

That will probably resolve the linkage error issue. But I don’t understand what’s the key factor to determine the storage class and what change should I put into my generated IR.

Moreover, I looked up the microsoft doc about storage class. The storage class 2 is described as "A value that Microsoft tools use for external symbols. " It doesn’t sound like a symbol represents a floating point constant at all.

Due to my limited knowledge of PE COFF and llvm codegen for windows platform, I am totally confused here. Any suggestion and hint are desperately welcomed!

I can’t speak for what past versions of LLVM used to do, but I can see that today for this IR, we generate an external symbol __real@40…:

declare dllimport void @my_function(double, double)
define i32 @main() {
call void @my_function(double 2.000000e+00, double 2.000000e+00)
ret i32 0

$ dumpbin -symbols t.o

006 00000000 SECT4 notype Static | .rdata
Section length 8, #relocs 0, #linenums 0, checksum 76DC4190, selection 2 (pick any)
008 00000000 SECT4 notype External | __real@4000000000000000

If you can provide complete IR on which llc produces a 0 storage class, that would be interesting, but otherwise there’s not much we can do.

Hi Reid,

Sure. Here I attach the trimmed IR(sim_0.ll) which llc.exe takes and produces a 0 storage class symbol.
The IR is fairly long but there is only 1 usage of real constant as actual argument passing to function iki_vlog_time() at line 137.
The version of llc.exe is

$ llc.exe --version
LLVM version 7.0.1
DEBUG build.
Default target: x86_64-pc-win32
Host CPU: skylake

The command I use to produce PE object is:

llc.exe -filetype=obj -O0 sim_0.ll -o sim_0.obj

Reid Kleckner <> 于2019年7月1日周一 下午1:45写道:

sim_0.ll (39 KB)

After some investigation, I see that this was unintended fallout from our triple canonicalization logic changes. The IR you attached has this line:
target triple = “x86_64-pc-win32”

Use a canonical triple instead to get the correct behavior:
target triple = “x86_64-windows-msvc”

I’ll fix LLVM so it treats these the same, but in the meantime, you can change your triple to fix the issue. I filed for it.

Hi Reid,

Thanks for filing the CR and pointing out the issue site.


Reid Kleckner <> 于2019年7月2日周二 下午3:25写道: