Lld-link does not export data symbols

I am experimenting with using lld to replace link.exe on Windows. I use the linker to create a DLL, specifying symbols to export on the command line like so:

clang++ -fuse-ld=lld -shared -Wl,-export:myfunc -Wl,-export:myvar ...

It seems, however, that lld will only export function symbols, not data symbols. If I try to export a variable, I get an error message:

lld-link: error: <root>: undefined symbol: myvar

Is there any way around this limitation? Any plans to support this in future versions of lld (I tried with LLVM 14.0.6)?

Update. A workaround is to add __declspec(dllexport) in the code for each exported symbol. But that doesn’t work for me, because the exported variable names are then mangled (“decorated”).

Did you mean __declspec(dllexport) instead of __declspec(dllimport)? The former marks symbols for exporting, whereas the latter marks them for importing.

I’m not able to reproduce the issue you’re seeing on LLVM main; I don’t have 14 on hand, but I’d be surprised if that had different behavior. I ran the following:

$ cat test.c
void privateFn() {}
int privateData = 1;
void publicFn() {}
int publicData = 0;

$ clang -target x86_64-windows -c test.c
$ lld-link -dll test.o -entry:privateFn -export:publicFn -export:publicData
$ llvm-readobj --coff-exports test.dll

File: test.dll
Format: COFF-x86-64
Arch: x86_64
AddressSize: 64bit
Export {
  Ordinal: 0
  Name:
  RVA: 0x0
}
Export {
  Ordinal: 1
  Name: publicData
  RVA: 0x3004
}
Export {
  Ordinal: 2
  Name: publicFn
  RVA: 0x1010
}

Do you have a small test case that reproduces the problem you’re seeing?

Yes, sorry. I corrected my post. And I will try to put together a small test case.

Yes. Just rename test.c to test.cpp and run clang++ instead of clang. lld-link then says:

lld-link: error: <root>: undefined symbol: publicData

Ah, got it. The root cause is that C++ mangles symbol names, e.g.

$ llvm-nm test.cpp
00000000 D ?privateData@@3HA
00000000 T ?privateFn@@YAXXZ
00000000 B ?publicData@@3HA
00000010 T ?publicFn@@YAXXZ
00000000 a @feat.00

There’s logic in LLD to try to find the mangled name corresponding to an unmangled name, but it’s limited and only handles functions. I’d recommend either specifying the mangled name explicity or using extern "C" to turn off name mangling for the particular symbols you care about.

1 Like

OK, turning mangling off with extern "C" does the trick, thank you. It is unfortunate, though, that lld-link is incompatible with link.exe, which apparently turns mangling off for you.

File a bug against lld-link about this?

Done: