Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
  • GHC GHC
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 5,413
    • Issues 5,413
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 603
    • Merge requests 603
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell CompilerGlasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #1288
Closed
Open
Issue created Apr 21, 2007 by jvlask@hotmail.com@trac-jvlask

ghci 6.6 foreign import stdcall broken, panic, panic!!!!

ghci 6.6 foreign import stdcall broken, panic, panic!!!!

I would like to report what I think is a problem with GHCI foreign function imports of c functions declared with stdcall calling convention (1) and also with loading objects containing dll imports (2).

WHAT IS THE PROBLEM ?

1. ghci handling of mangling of stdcall function names broken

Prelude> :load htest3
[1 of 1] Compiling Main             ( htest3.hs, interpreted )

During interactive linking, GHCi couldn't find the following symbol:
  test
This may be due to you not asking GHCi to load extra object files,
archives or DLLs needed by your current session.  Restart GHCi, specifying
the missing library using the -L/path/to/object/dir and -lmissinglibname
flags, or simply by naming the relevant files on the GHCi command line.
Alternatively, this link failure might indicate a bug in GHCi.
If you suspect the latter, please send a bug report to:
  glasgow-haskell-bugs@haskell.org

2. ghci loading of c object files dll imports name resolution broken

>ghci -fglasgow-exts test_proxy5a.o -ltest3b

test_proxy5a.o: unknown symbol `__imp__test'
final link ... : linking extra libraries/objects failed

detail follows ...

CONCLUSSION REACHED

1. Importing Stdcall Symbols

ghci dose not correctly look for symbols decorated in the stdcall manner in the object files ie. it looks for _test when it should (according to stdcall convention) look for _test@4.

stdcall symbols in object files are decorated with the number of bytes that should be popped from the stack before the function returns.

2. linking objects with dllimports

ghci cannot properly resolve dllimports in c object files i.e. if an object loaded by ghci (eg test_proxy, with c function test_proxy) calls functions from a dll (eg test) then that function in the object file will be decorated as __imp__test this in normal course linked agains a .lib or a .a file will be resolved to _test function in the dll but ghci does not do this.

Offcourse these problems go away when using ghc ... but well what's the point of ghci then?

SUMMARY OF TESTS and METHODOLOGY

1. Reference Case

verify that ccall works ..

[[BR]]Create c file test1a.c and function test(int) in the file [[BR]]create haskell file htest1.hs with function ctest calling test [[BR]]check this works ok with

a. c object loaded (test1a.c, htest1.hs )-- OK, RIGHT [[BR]] b. windows dll, c is function a dll export (test1b.c, htest1.hs ) -- OK, RIGHT

== 3. change calling convention to stdcall ==

a. check loading of function from object (test3a.c, htest3.hs) -- FAIL, WRONG[[BR]] b. check loading of stdcall function from dll -- FAIL, WRONG

4. try what shouldn't work

a. htest3 against object test1a

i.e. what hapens when you try loading a haskell module with foreign import stdcall against c function declared with ccall convention.

ghci loaded -- OK!!, WRONG,

it should not have resolved the symbol and not loaded.[[BR]]

ghci called the function and crashed -- given that it resolved the symbol and called the function, this is expected.

b. htest3 against dll htest1b.dll

same result as 4a -- expected,

behaviour consistent in both cases with resolving stdcall callouts (symbol test) in a manner consistent with ccalls. i.e. resolving the call to c function test as a call to symbol _test rather than _test@4 as it should be according to the stdcall convention.

yet the function is called as a stdcall c function, consequently ghci crashes when the ccall function returns and the stack has not been cleared of the function arguments, as is required by the stdcall convention.

5. Lets try a proxy function/object

Hmm, lets see what happens when we have a ccall c proxy function calling stdcall c function in dll etc?

a. test_proxy5a.o with test3b.dll

ccall function calling stdcall function in dll

unknown symbol __imp__test

FAILED, WRONG.

dllimports are decorated with __imp__ so a stdcall dllimport to a c function

test will appear as __imp__test@4

the dll will export symbol _test@4, usually it is the function of the import

library ( .a or .lib depending upon which linker mingw or msvc ) to resolve

__imp_test@4 to reference _test@4 in the dll

b. test_proxy5b.o with test3b.dll, htest5.hs

ccall function calling stdcall function (not declared as dllimport)

LOADS OK, RUNS OK

test_proxy5b imports symbol _test@4 the test3b.dll exports symbol

_test@4. Arguably this is correct behaviour as __imp__ decoration is an

MS innovation and case (a) should be handled together with case (b).

c. whell what about test_proxy5b.o with test1b.dll

i.e. c stdcall to a c function declared with ccall convention from .o object

loaded by ghci should fail to resolve symbols, should crash program but does niether ????

hey this has me stumped test_proxy5b.o imports symbol _test@4. test1b.dll

exports symbol _test hmmm how is the symbol _test@4 resolved ??? why

isn't the stack corrupted when test is called ??? MYSTERY ???

DETAIL

compiler: ghci version 6.6
platform: windows XP

notes-

  • test1[a,b].c
  • test3[a,b].c

difference in these files between a,b version is that the b version declares dllexport, required when building a dll with msvc (and not using def file), not relevant with mingw and using "dllwrap --export-all-symbols"

TEST 1

test1a.c

#include <stdio.h>

void test(int arg)
{
   printf("The argument passed was %i\n", arg );
}

test1b.c

#include <stdio.h>

__declspec(dllexport) void test(int arg)
{
   printf("The argument passed was %i\n", arg );
}

htest1.hs

import Foreign
import Foreign.C


foreign import ccall "test" ctest :: CInt -> IO ()

COMPILATION OF C DLL/OBJECTS

gcc -c test1a.c
gcc -c test1b.c
ar -rv test1b.a test1b.o
dllwrap --export-all-symbols --output-lib test1b.dll.a -o test1b.dll test1b.a

TEST 1A results

ghci -fglasgow-exts test1a.o
Loading package base ... linking ... done.
Loading object (static) test1a.o ... done
final link ... done
Prelude> :load htest1
[1 of 1] Compiling Main             ( htest1.hs, interpreted )
Ok, modules loaded: Main.
*Main> ctest 5
The argument passed was 5
*Main>

TEST 1B

ghci -fglasgow-exts -ltest1b
Loading package base ... linking ... done.
Loading object (dynamic) test1b ... done
final link ... done

Prelude> :load htest1
[1 of 1] Compiling Main             ( htest1.hs, interpreted )
Ok, modules loaded: Main.
*Main> ctest 5
The argument passed was 5
*Main>

TEST 3

test3a.c

#include <stdio.h>

void _stdcall test(int arg)
{
   printf("The argument passed was %i\n", arg );
}

test3b.c

#include <stdio.h>

__declspec(dllexport) void _stdcall test(int arg)
{
   printf("The argument passed was %i\n", arg );
}

htest3.hs

import Foreign
import Foreign.C


foreign import stdcall "test" ctest :: CInt -> IO ()

COMPILATION OF C DLL/OBJECTS

compilation (mingw)
gcc -c test3a.c
gcc -c test3b.c
ar -rv test3b.a test3b.o
E:\vvv\WP03\S00\ffi>dllwrap --export-all-symbols --output-lib test3b.dll.a -o 

test3b.dll test3b.a

compilation msvc (same result with both mingw and msvc dll!!)
cl -c test3.c
link etc ...

TEST 3A

ghci -fglasgow-exts test3a.o
Loading package base ... linking ... done.
Loading object (static) test3a.o ... done
final link ... done

Prelude> :load htest3.hs
[1 of 1] Compiling Main             ( htest3.hs, interpreted )

During interactive linking, GHCi couldn't find the following symbol:
  test

TEST 3B

ghci -fglasgow-exts -ltest3b
Loading package base ... linking ... done.
Loading object (dynamic) test3b ... done
final link ... done

Prelude> :load htest3.hs
[1 of 1] Compiling Main             ( htest3.hs, interpreted )

During interactive linking, GHCi couldn't find the following symbol:
  test

the actual symbol in the object file is _test@4

TEST 4A

ghci -fglasgow-exts test1a.o
Prelude> :load htest3
[1 of 1] Compiling Main             ( htest3.hs, interpreted )
Ok, modules loaded: Main.
*Main> ctest 5
The argument passed was 5
  1. .. ghci then crashes .... as expected ...

after all ccall function was called using the stdcall calling convention ! but the module should not have loaded as ghci should have been looking for a _test@4 symbol

TEST 5

test_proxy5a.c

#include <stdio.h>

__declspec(dllimport) void _stdcall test(int arg);

void test_proxy(int arg)
{
   test(arg);
}

test_proxy5a.c

#include <stdio.h>

void _stdcall test(int arg); 

void test_proxy(int arg)
{
   test(arg);
}

htest5.hs

module Main where

import Foreign
import Foreign.C


foreign import ccall "test_proxy" ctest :: CInt -> IO ()

COMPILATION OF C OBJECTS

gcc -c test_proxy5a.c
gcc -c test_proxy5b.c

TEST 5A

E:\vvv\WP03\S00\ffi>ghci -fglasgow-exts test_proxy5a.o -ltest3b
   ___         ___ _
  / _ \ /\  /\/ __(_)
 / /_\// /_/ / /  | |      GHC Interactive, version 6.6, for Haskell 98.
/ /_\\/ __  / /___| |      http://www.haskell.org/ghc/
\____/\/ /_/\____/|_|      Type :? for help.

Loading package base ... linking ... done.
Loading object (static) test_proxy5a.o ... done
Loading object (dynamic) test3b ... done
:
test_proxy5a.o: unknown symbol `__imp__test'
final link ... : linking extra libraries/objects failed

TEST 5B

E:\vvv\WP03\S00\ffi>ghci -fglasgow-exts test_proxy5b.o -ltest3b
   ___         ___ _
  / _ \ /\  /\/ __(_)
 / /_\// /_/ / /  | |      GHC Interactive, version 6.6, for Haskell 98.
/ /_\\/ __  / /___| |      http://www.haskell.org/ghc/
\____/\/ /_/\____/|_|      Type :? for help.

Loading package base ... linking ... done.
Loading object (static) test_proxy5b.o ... done
Loading object (dynamic) test3b ... done
final link ... done
Prelude> :load htest5
[1 of 1] Compiling Main             ( htest5.hs, interpreted )
Ok, modules loaded: Main.
*Main> ctest 5
The argument passed was 5
*Main>

TEST 5C

E:\vvv\WP03\S00\ffi>ghci -fglasgow-exts test_proxy5b.o -ltest1b
   ___         ___ _
  / _ \ /\  /\/ __(_)
 / /_\// /_/ / /  | |      GHC Interactive, version 6.6, for Haskell 98.
/ /_\\/ __  / /___| |      http://www.haskell.org/ghc/
\____/\/ /_/\____/|_|      Type :? for help.

Loading package base ... linking ... done.
Loading object (static) test_proxy5b.o ... done
Loading object (dynamic) test1b ... done
final link ... done
Prelude> :load htest5
[1 of 1] Compiling Main             ( htest5.hs, interpreted )
Ok, modules loaded: Main.
*Main> ctest 5
The argument passed was 5
*Main> ctest 5
The argument passed was 5
Trac metadata
Trac field Value
Version 6.6
Type Bug
TypeOfFailure OtherFailure
Priority high
Resolution Unresolved
Component GHCi
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking