[GHC] #15094: unknown symbol `___divmoddi4' error with clock on 32-bit windows
#15094: unknown symbol `___divmoddi4' error with clock on 32-bit windows --------------------------------+--------------------------------- Reporter: simonmic | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.6.1 Component: Compiler | Version: 8.4.2 Keywords: | Operating System: Windows Architecture: x86 | Type of failure: None/Unknown Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: --------------------------------+--------------------------------- I got this error when building with 32-bit ghc 8.4.2 on appveyor: {{{ -- While building custom Setup.hs for package hledger-lib-1.9.99 using: C:\sr\setup-exe-cache\i386-windows\Cabal- simple_Z6RU0evB_2.2.0.1_ghc-8.4.2.exe --builddir=.stack-work\dist\ba067387 build lib:hledger-lib --ghc-options " -ddump-hi -ddump-to-file" Process exited with code: ExitFailure 1 Logs have been written to: C:\pr\.stack-work\logs\hledger- lib-1.9.99.log Configuring hledger-lib-1.9.99... Preprocessing library for hledger-lib-1.9.99.. Building library for hledger-lib-1.9.99.. [ 1 of 48] Compiling Hledger.Utils.Color ( Hledger\Utils\Color.hs, .stack-work\dist\ba067387\build\Hledger\Utils\Color.o ) [ 2 of 48] Compiling Hledger.Utils.Test ( Hledger\Utils\Test.hs, .stack-work\dist\ba067387\build\Hledger\Utils\Test.o ) [ 3 of 48] Compiling Hledger.Utils.UTF8IOCompat ( Hledger\Utils\UTF8IOCompat.hs, .stack- work\dist\ba067387\build\Hledger\Utils\UTF8IOCompat.o ) [ 4 of 48] Compiling Hledger.Utils.Regex ( Hledger\Utils\Regex.hs, .stack-work\dist\ba067387\build\Hledger\Utils\Regex.o ) [ 5 of 48] Compiling Hledger.Utils.Tree ( Hledger\Utils\Tree.hs, .stack-work\dist\ba067387\build\Hledger\Utils\Tree.o ) [ 6 of 48] Compiling Hledger.Data.Types ( Hledger\Data\Types.hs, .stack-work\dist\ba067387\build\Hledger\Data\Types.o ) ghc.EXE: unable to load package `clock-0.7.2' ghc.EXE: | C:\sr\snapshots\673e3da0\lib\i386-windows- ghc-8.4.2\clock-0.7.2-Cf9UTsaN2AjEpBnoMpmgkU\HSclock-0.7.2-Cf9UTsaN2AjEpBnoMpmgkU.o: unknown symbol `___divmoddi4' Command exited with code 1 APPVEYOR_SAVE_CACHE_ON_ERROR is set to 'true' - cache will be updated }}} https://ci.appveyor.com/project/simonmichael/hledger/build/master-404 We think this is related: https://github.com/zfsonlinux/zfs/issues/6417 -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15094> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#15094: unknown symbol `___divmoddi4' error with clock on 32-bit windows ---------------------------------+------------------------------ Reporter: simonmic | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.6.1 Component: Compiler | Version: 8.4.2 Resolution: | Keywords: Operating System: Windows | Architecture: x86 Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | ---------------------------------+------------------------------ Changes (by bgamari): * cc: Phyx- (added) Comment: Strange that we don't see this on Linux i386. Any idea what might be going on here, Phyx? -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15094#comment:1> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#15094: unknown symbol `___divmoddi4' error with clock on 32-bit windows ---------------------------------+------------------------------ Reporter: simonmic | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.6.1 Component: Compiler | Version: 8.4.2 Resolution: | Keywords: Operating System: Windows | Architecture: x86 Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | ---------------------------------+------------------------------ Comment (by Phyx-): It's a problem with the library. `x86` doesn't have a `64 bit` (`DImode`) `divmod` instruction. So GCC emulates it using a compiler built-in `___divmoddi4`. Since the library uses this built-in it needs to link against `libgcc`. It's not a problem for x86 Linux because of `dynamic-way`. When the `so` is made GCC links in `libgcc` so the problem doesn't show. Using non- dynamic-way will have the same issue on Linux as well. The clock library needs to add `extra-libraries: gcc`. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15094#comment:2> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#15094: unknown symbol `___divmoddi4' error with clock on 32-bit windows ---------------------------------+------------------------------ Reporter: simonmic | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.6.1 Component: Compiler | Version: 8.4.2 Resolution: | Keywords: Operating System: Windows | Architecture: x86 Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | ---------------------------------+------------------------------ Comment (by RyanGlScott): I might be slow on the uptake here, but I don't see how the `clock` library is using `divmod` (directly, at least). The only `foreign import`s that `clock` uses reference [https://github.com/corsis/clock/blob/00435ddf926b3603a3576d98e44763d165d2ec2... its own C file], which is: {{{#!c #ifdef _WIN32 #include <windows.h> #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) #define U64(x) x##Ui64 #else #define U64(x) x##ULL #endif #define DELTA_EPOCH_IN_100NS U64(116444736000000000) static long ticks_to_nanos(LONGLONG subsecond_time, LONGLONG frequency) { return (long)((1e9 * subsecond_time) / frequency); } static ULONGLONG to_quad_100ns(FILETIME ft) { ULARGE_INTEGER li; li.LowPart = ft.dwLowDateTime; li.HighPart = ft.dwHighDateTime; return li.QuadPart; } static void to_timespec_from_100ns(ULONGLONG t_100ns, long long *t) { t[0] = (long)(t_100ns / 10000000UL); t[1] = 100*(long)(t_100ns % 10000000UL); } void hs_clock_win32_gettime_monotonic(long long* t) { LARGE_INTEGER time; static LARGE_INTEGER frequency; static int hasFreq = 0; QueryPerformanceCounter(&time); if (!hasFreq) { hasFreq = 1; QueryPerformanceFrequency(&frequency); } // seconds t[0] = time.QuadPart / frequency.QuadPart; // nanos = t[1] = ticks_to_nanos(time.QuadPart % frequency.QuadPart, frequency.QuadPart); } void hs_clock_win32_gettime_realtime(long long* t) { FILETIME ft; ULONGLONG tmp; GetSystemTimeAsFileTime(&ft); tmp = to_quad_100ns(ft); tmp -= DELTA_EPOCH_IN_100NS; to_timespec_from_100ns(tmp, t); } void hs_clock_win32_gettime_processtime(long long* t) { FILETIME creation_time, exit_time, kernel_time, user_time; ULONGLONG time; GetProcessTimes(GetCurrentProcess(), &creation_time, &exit_time, &kernel_time, &user_time); // Both kernel and user, acc. to http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_0... time = to_quad_100ns(user_time) + to_quad_100ns(kernel_time); to_timespec_from_100ns(time, t); } void hs_clock_win32_gettime_threadtime(long long* t) { FILETIME creation_time, exit_time, kernel_time, user_time; ULONGLONG time; GetThreadTimes(GetCurrentThread(), &creation_time, &exit_time, &kernel_time, &user_time); // Both kernel and user, acc. to http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_0... time = to_quad_100ns(user_time) + to_quad_100ns(kernel_time); to_timespec_from_100ns(time, t); } void hs_clock_win32_getres_monotonic(long long* t) { LARGE_INTEGER frequency; QueryPerformanceFrequency(&frequency); ULONGLONG resolution = U64(1000000000)/frequency.QuadPart; t[0] = resolution / U64(1000000000); t[1] = resolution % U64(1000000000); } void hs_clock_win32_getres_realtime(long long* t) { t[0] = 0; t[1] = 100; } void hs_clock_win32_getres_processtime(long long* t) { t[0] = 0; t[1] = 100; } void hs_clock_win32_getres_threadtime(long long* t) { t[0] = 0; t[1] = 100; } #endif /* _WIN32 */ }}} Surely this shouldn't require linking against `gcc` to work, no? -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15094#comment:3> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#15094: unknown symbol `___divmoddi4' error with clock on 32-bit windows ---------------------------------+------------------------------ Reporter: simonmic | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.6.1 Component: Compiler | Version: 8.4.2 Resolution: | Keywords: Operating System: Windows | Architecture: x86 Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | ---------------------------------+------------------------------ Comment (by Phyx-): It does. It's right there in {{{ void hs_clock_win32_gettime_monotonic(long long* t) { LARGE_INTEGER time; LARGE_INTEGER frequency; QueryPerformanceCounter(&time); QueryPerformanceFrequency(&frequency); // seconds t[0] = time.QuadPart / frequency.QuadPart; // nanos = t[1] = ticks_to_nanos(time.QuadPart % frequency.QuadPart, frequency.QuadPart); } }}} At the optimization level `clock` is requesting, namely `-O3` GCC will do multiplication widening optimizations. This optimize `time.QuadPart / frequency.QuadPart` and `time.QuadPart % frequency.QuadPart` into a single `divmod`. It even says so {{{ Pass statistics of "widening_mul": ---------------- divmod calls inserted: 1 hs_clock_win32_gettime_monotonic (long long intD.8 * tD.60113) { # PT = nonlocal null long long intD.8 * t_9(D) = tD.60113; union LARGE_INTEGERD.2224 frequencyD.60117; union LARGE_INTEGERD.2224 timeD.60116; long long intD.8 _1; long long intD.8 _2; long long intD.8 _3; long long intD.8 _4; long long intD.8 _5; doubleD.23 _11; doubleD.23 _15; doubleD.23 _16; doubleD.23 _17; long intD.3 _18; __complex__ long long intD.8 divmod_tmp_19; ;; basic block 2, loop depth 0, count 0, freq 10000, maybe hot ;; prev block 0, next block 1, flags: (NEW, REACHABLE, VISITED) ;; pred: ENTRY [100.0%] (FALLTHRU,EXECUTABLE) # .MEM_7 = VDEF <.MEM_6(D)> # USE = nonlocal { D.60116 D.60117 } (escaped) # CLB = nonlocal { D.60116 D.60117 } (escaped) QueryPerformanceCounter@4D.8347 (&timeD.60116); # .MEM_8 = VDEF <.MEM_7> # USE = nonlocal { D.60116 D.60117 } (escaped) # CLB = nonlocal { D.60116 D.60117 } (escaped) QueryPerformanceFrequency@4D.8349 (&frequencyD.60117); # VUSE <.MEM_8> _1 = timeD.60116.QuadPartD.2223; # VUSE <.MEM_8> _2 = frequencyD.60117.QuadPartD.2223; divmod_tmp_19 = DIVMOD (_1, _2); <---- divmod inserted here. - Phyx _3 = REALPART_EXPR <divmod_tmp_19>; # .MEM_10 = VDEF <.MEM_8> *t_9(D) = _3; # RANGE [-9223372036854775807, 9223372036854775807] _4 = IMAGPART_EXPR <divmod_tmp_19>; _11 = (doubleD.23) _4; _15 = _11 * 1.0e+9; _16 = (doubleD.23) _2; _17 = _15 / _16; _18 = (long intD.3) _17; # RANGE [-2147483648, 2147483647] _5 = (long long intD.8) _18; # .MEM_12 = VDEF <.MEM_10> MEM[(long long intD.8 *)t_9(D) + 8B] = _5; # .MEM_13 = VDEF <.MEM_12> timeD.60116 ={v} {CLOBBER}; # .MEM_14 = VDEF <.MEM_13> frequencyD.60117 ={v} {CLOBBER}; # VUSE <.MEM_14> return; ;; succ: EXIT [100.0%] (EXECUTABLE) } }}} This entire file, always uses 64 bit types. You have no hardware support for 64 bit `divmod`. The compiler is smart enough to know this and expands the built-in `DIVMOD` to a library call which is expected to do the operation. The implementation for the call is in `libgcc`. The explicit purpose for `libgcc` is to handle these calls the compiler emits to do the software emulation[1]. {{{ GCC provides a low-level runtime library, libgcc.a or libgcc_s.so.1 on some platforms. GCC generates calls to routines in this library automatically, whenever it needs to perform some operation that is too complicated to emit inline code for. Most of the routines in libgcc handle arithmetic operations that the target processor cannot perform directly. This includes integer multiply and divide on some machines, and all floating-point and fixed-point operations on other machines. libgcc also includes routines for exception handling, and a handful of miscellaneous operations. }}} So yes, using a complex operation that the architecture has no support for requires explicit software emulation, and thus requires compiling against `libgcc`. Or turning off the optimization. Possibly for that function alone using an attribute. Either way, this is not a GHC bug. [1] https://gcc.gnu.org/onlinedocs/gccint/Libgcc.html -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15094#comment:4> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#15094: unknown symbol `___divmoddi4' error with clock on 32-bit windows ---------------------------------+------------------------------ Reporter: simonmic | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.6.1 Component: Compiler | Version: 8.4.2 Resolution: | Keywords: Operating System: Windows | Architecture: x86 Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | ---------------------------------+------------------------------ Comment (by RyanGlScott): I see. In that case, how should `clock` be patched so as to ensure backwards compatibility with old versions of GHC? On 32-bit GHC 8.4.2, at least, this patch suffices: {{{#!diff diff --git a/clock.cabal b/clock.cabal index 67d232e..1b21682 100644 --- a/clock.cabal +++ b/clock.cabal @@ -74,6 +74,10 @@ library c-sources: cbits/hs_clock_darwin.c if os(windows) c-sources: cbits/hs_clock_win32.c + + -- See https://ghc.haskell.org/trac/ghc/ticket/15094 + if arch(i386) + extra-libraries: gcc_s_dw2-1 include-dirs: cbits ghc-options: -O3 -Wall }}} Should that work for other GHCs as well? -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15094#comment:5> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#15094: unknown symbol `___divmoddi4' error with clock on 32-bit windows ---------------------------------+------------------------------ Reporter: simonmic | Owner: (none) Type: bug | Status: closed Priority: normal | Milestone: 8.6.1 Component: Compiler | Version: 8.4.2 Resolution: invalid | Keywords: Operating System: Windows | Architecture: x86 Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | ---------------------------------+------------------------------ Changes (by RyanGlScott): * status: new => closed * resolution: => invalid Comment: I've opened a pull request against `clock` at https://github.com/corsis/clock/pull/51, so I'll close this. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15094#comment:6> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#15094: unknown symbol `___divmoddi4' error with clock on 32-bit windows ---------------------------------+------------------------------ Reporter: simonmic | Owner: (none) Type: bug | Status: closed Priority: normal | Milestone: 8.6.1 Component: Compiler | Version: 8.4.2 Resolution: invalid | Keywords: Operating System: Windows | Architecture: x86 Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | ---------------------------------+------------------------------ Comment (by Phyx-): While that will work, it will break the compiler's ability to be able to decide between static and dynamic linking. So I recommended `extra- libraries: gcc` for this exact reason and that linking against dlls directly is just asking for trouble like the postgres ticket. But older gcc before 8.2 won't work with just `gcc`. Also depending on the license if libgcc (LGPL vs GPL) this change may make clock unusable for commercial development. In this specific case I would have just turned off the Optimization for that function. Instead of linking an entire library in just for an optimization that won't really give you any gain in this case. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15094#comment:7> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#15094: unknown symbol `___divmoddi4' error with clock on 32-bit windows ---------------------------------+------------------------------ Reporter: simonmic | Owner: (none) Type: bug | Status: closed Priority: normal | Milestone: 8.6.1 Component: Compiler | Version: 8.4.2 Resolution: invalid | Keywords: Operating System: Windows | Architecture: x86 Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | ---------------------------------+------------------------------ Comment (by RyanGlScott): OK. Do you mind saying this on the GitHub PR, and showing how the optimization can be disabled for that one particular function? (I'm rather unfamiliar with GCC attributes.) -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15094#comment:8> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#15094: unknown symbol `___divmoddi4' error with clock on 32-bit windows ---------------------------------+------------------------------ Reporter: simonmic | Owner: (none) Type: bug | Status: closed Priority: normal | Milestone: 8.6.1 Component: Compiler | Version: 8.4.2 Resolution: invalid | Keywords: Operating System: Windows | Architecture: x86 Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | ---------------------------------+------------------------------ Comment (by Phyx-): Sure, I'll comment when I get home later tonight -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15094#comment:9> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
participants (1)
-
GHC