Thread overview
LDC lto generate wrong dll export table
May 22, 2022
Test123
May 22, 2022
Test123
May 22, 2022
Test123
May 22, 2022
Test123
May 22, 2022
Test123
May 23, 2022
kinke
May 22, 2022

The problem is when link with LDC generate lto object, there is no export table name.

ldmd2 -mtriple=x86_64-w64-mingw32 -betterC -flto=full -c ./test.d

import ldc.attributes : assumeUsed;
import core.sys.windows.windows;
@nogc nothrow extern(C):
export int test() @assumeUsed {
        return 0;
}

export extern(Windows) BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) @assumeUsed {
        return true;
}

x86_64-w64-mingw32-clang -flto=full ./test.c -c

#include <windows.h>

BOOL WINAPI DllMain(HINSTANCE hinst,DWORD reason,LPVOID lpReserved)
{
	return TRUE;
}

__declspec(dllexport) int test(){
	return 0;
}

to link with lld (or use clang -L/dll -shared)

lld -flavor ld -lmsvcrt -m i386pep --shared -Bdynamic -e DllMainCRTStartup --enable-auto-image-base -o test.dll mingw/x86_64-w64-mingw32/lib/dllcrt2.o mingw/x86_64-w64-mingw32/lib/crtbegin.o -Lmingw/x86_64-w64-mingw32/lib -Lmingw/lib -Lmingw/x86_64-w64-mingw32/sys-root/mingw/lib -Lmingw/lib/clang/14.0.0/lib/windows test.o -ldnsapi -lbcrypt -lpsapi -lole32 -liphlpapi -luserenv /dll -lws2_32 -lssp_nonshared -lmingw32 mingw/lib/clang/14.0.0/lib/windows/libclang_rt.builtins-x86_64.a -lmoldname -lmingwex -ladvapi32 -lshell32 -luser32 -lkernel32 mingw/x86_64-w64-mingw32/lib/crtend.o -Bdynamic

As you can see, c and d code are same, and use same link argument. (I replace the test.o with link script to test)

If I build D code without LTO, I get the correct binary like clang dose.

Only when I build code with LDC and LTO, the problem exists:

Verify with x86_64-w64-mingw32-objdump --private-headers test.dll, you will see random symbol name for LDC & LDC bianry(some time empty).

May 22, 2022

On Sunday, 22 May 2022 at 17:06:46 UTC, Test123 wrote:

>

The problem is when link with LDC generate lto object, there is no export table name.

to viery this please download https://github.com/mstorsjo/llvm-mingw/releases/download/20220323/llvm-mingw-20220323-msvcrt-ubuntu-18.04-x86_64.tar.xz into linux(there is also macOS and Windows version).

test with clang:

./mingw/bin/x86_64-w64-mingw32-clang -flto=full ./test.c -c
./mingw/bin/lld -flavor ld -lmingwex -lmingw32 -lmsvcrt -lkernel32 -m i386pep --shared -Bdynamic test.o -o test.dll -e DllMainCRTStartup --enable-auto-image-base  mingw/x86_64-w64-mingw32/lib/dllcrt2.o mingw/x86_64-w64-mingw32/lib/crtbegin.o -Lmingw/x86_64-w64-mingw32/lib -Lmingw/lib -Lmingw/x86_64-w64-mingw32/sys-root/mingw/lib -Lmingw/lib/clang/14.0.0/lib/windows /dll mingw/lib/clang/14.0.0/lib/windows/libclang_rt.builtins-x86_64.a mingw/x86_64-w64-mingw32/lib/crtend.o -Bdynamic
./mingw/bin/x86_64-w64-mingw32-objdump --private-headers  ./test.dll

And you will see this at the end:

Export Table:
 DLL name: test.dll
 Ordinal base: 0
 Ordinal      RVA  Name
       0        0
       1   0x2350  test

verify with ldc

ldmd2 -mtriple=x86_64-w64-mingw32 -betterC -flto=full -c ./test.d
./mingw/bin/lld -flavor ld -lmingwex -lmingw32 -lmsvcrt -lkernel32 -m i386pep --shared -Bdynamic test.o -o test.dll -e DllMainCRTStartup --enable-auto-image-base  mingw/x86_64-w64-mingw32/lib/dllcrt2.o mingw/x86_64-w64-mingw32/lib/crtbegin.o -Lmingw/x86_64-w64-mingw32/lib -Lmingw/lib -Lmingw/x86_64-w64-mingw32/sys-root/mingw/lib -Lmingw/lib/clang/14.0.0/lib/windows /dll mingw/lib/clang/14.0.0/lib/windows/libclang_rt.builtins-x86_64.a mingw/x86_64-w64-mingw32/lib/crtend.o -Bdynamic
./mingw/bin/x86_64-w64-mingw32-objdump --private-headers  ./test.dll

you will this this at the end:

Export Table:
 DLL name: test.dll
 Ordinal base: 0
 Ordinal      RVA  Name
       0        0
       1   0x2340
       2   0x2330  t

The name for ldc2 wll be random(some time empty).

Use ldc2 without LTO always give the same result like clang.

May 22, 2022

On Sunday, 22 May 2022 at 17:27:28 UTC, Test123 wrote:

>

Use ldc2 without LTO always give the same result like clang.

confirm with LDC 1.28.1, 1.30.0-beta1.

When you have one short export symbol LDC unlikely generate wrong result, when there is more than one export it never generate right result.

#include <windows.h>
__declspec(dllexport) int test1(){
	return 0;
}

__declspec(dllexport) int test2(){
        return 0;
}

clang wlways generate correct test.dll.

LDC give wrong result when more than one export is used with LTO:

import ldc.attributes : assumeUsed;

export extern(C) int test1() @assumeUsed {
        return 0;
}

export extern(C) int test2() @assumeUsed {
        return 0;
}

remove test1 or test2 will give you right result with LTO.

but if you use a long function name like test111242342343243243, ldc will alway give wrong result with LTO.

May 22, 2022

On Sunday, 22 May 2022 at 17:50:49 UTC, Test123 wrote:

>

Use ldc2 without LTO always give the same result like clang.

I find a workaround, use ldc --output-ll generate ll file, then use clang build ll into object file with LTO, will fix the problem.

May 22, 2022

On Sunday, 22 May 2022 at 18:17:45 UTC, Test123 wrote:

>

On Sunday, 22 May 2022 at 17:50:49 UTC, Test123 wrote:

>

Use ldc2 without LTO always give the same result like clang.

I find a workaround, use ldc --output-ll generate ll file, then use clang build ll into object file with LTO, will fix the problem.

Sadlly this will not work for a big project, cause some symbol not find problem. (not sure why)

I hope this can be fixed ASAP with the information I provide.

any suggestion will be much appreciated.

May 23, 2022

On Sunday, 22 May 2022 at 19:54:33 UTC, Test123 wrote:

>

I hope this can be fixed ASAP with the information I provide.

Nope - MinGW isn't a supported target. Your example works fine when using the (default) MSVC target.