[Vm-dev] ffi-test-main.c fails on FreeBSD

Eliot Miranda eliot.miranda at gmail.com
Fri Nov 20 17:30:57 UTC 2009

On Fri, Nov 20, 2009 at 3:26 AM, Gary Dunn <osp at aloha.com> wrote:

> I can report progress but no solution.
> 1. Since ffi-test-main failed to build with a simple "make" I had
> assumed I needed to use libffi. I added a print statement to show the
> values at the point of failure at line 361, the CHECK statement:
>    ffiInitialize();
>    for (ul= 0;  ul < 15;  ++ul)
>      ffiPushSingleFloat(fa[ul]);
>    GO(FFITypeSingleFloat, many);
>    f= ffiReturnFloatValue();
>    ffiCleanup();
>     printf("%g %g %g %g\n", f, ff, f - ff, FLT_EPSILON);
>     CHECK(f - ff < FLT_EPSILON);
> It gave f and ff to be identical, f - ff zero, and FLT_EPSILON a very
> small value. The strange thing was that the test did not fail. I
> commented out my print statement and it failed. Weird.
> I noticed I was not seeing the output from puts statements. Recalling
> that this is typically a macro I looked to see if it had been defined,
> and found this near the top of the file:
> #if 0
> # define dprintf(ARGS)  printf ARGS
> # define puts(ARG)      puts(ARG)
> #else
> # define dprintf(ARGS)
> # define puts(ARG)
> #endif
> I changed the zero to one and the output was verbose. No failure, even
> with my print statement commented out.
> I suspect there is some tricky coding here that works on some versions
> of C and not others. The preprocessor, especially.
> So I got to wondering why make without args failed. I traced the problem
> to these lines from the Makefile
> CPU=    $(shell ./ffi-config -cpu)
> ABI=    $(shell ./ffi-config -abi)
> LIB=    $(shell ./ffi-config -lib)
> Running them manually gave x86, sysv and blank, but
> OBJ=    ffi-test-main.o ffi-test.o $(CPU)-$(ABI).o $(CPU)-$(ABI)-asm.o
> resolved to ffi-test-main.o ffi-test.o -.o --asm.o
> which caused make to complain that it did not know how to make -.o.
> I substituted like this
> #OBJ=    ffi-test-main.o ffi-test.o $(CPU)-$(ABI).o $(CPU)-$(ABI)-asm.o
> OBJ=   ffi-test-main.o ffi-test.o x86-sysv.o x86-sysv-asm.o
> and the build completed.
> Eventually I figured out that the shell construct works in gnu make.
> FreeBSD does not use gnu make. It is available as gmake. I put back the
> Makefile and used gmake and got a good build.
> The results are inconclusive. The output is
> slate01# ./main
> passed ffi assertions (0 failed)
> Problem passing 64bit structures
> Is that because I am not using a 64bit CPU? Is that a show stopper?
> Apparently not.
> The thing is, this does not fix the real problem. If I load my 3.9 image
> and install the FFI package from SqueakMap, then run the FFI-Tests in
> SUnit runner I get 21 run, 0 passes, 0 expected failures, 0 failures, 21
> errors, 0 unexpected passes. When I click on a result and open a
> debugger I find
> Error: Unable to find function address
> invokeWithArguments: argArray
>        "Manually invoke the receiver, representing an external function."
>        <primitive: 'primitiveCalloutWithArgs' module:'SqueakFFIPrims'>
>        ^self externalCallFailed
> externalCallFailed
>        "Raise an error after a failed call to an external function"
>        | errCode |
>        errCode := ExternalFunction getLastError. "this allows us to look at
> the actual error code"
>        ^self error: (ExternalFunction errorMessageFor: errCode).
> error: aString
>        "Throw a generic Error exception."
>        ^Error new signal: aString
> If the  ffi-test-main.c tests are passing, why are the SUnit tests all
> failing? Is that 64bit thing a big deal?

twice as big a deal as 32-bits...  But seriously folks...

Have you built a SqueakFFIPrims shared object?  Have you installed it in the
right directory with other plugins?  Is the export table in SqueakFFIPrims.c
correct (calls itself SqueakFFIPrims, includes both primitiveCallout and
primitiveCalloutWithArgs as exports).

First try and understand

invokeWithArguments: argArray
       "Manually invoke the receiver, representing an external function."
       <primitive: 'primitiveCalloutWithArgs' module:'SqueakFFIPrims'>
       ^self externalCallFailed

and Error: Unable to find function address.

The first is a method that includes a spec for calling a plugin primitive,
in the SqueakFFIPrims plugin, which could be in a shared object, a dll or a
bundle depending on platform.  You're on linux so it should be in either
SqueakFFIPrims or SqueakFFIPrims.so depending on which version of the VM
you're working on.

The second tells you that, probably the VM is finding the SqueakFFIPrims
module but its not finding primitiveCalloutWithArgs within it.  You can
check by tracing execution through
ioLoadExternalFunctionOfLengthFromModuleOfLength.  Assuming the module is
being found you need to find out why the function isn't being found.

At the end of SqueakFFIPrims.c you should see a table that looks something


void* SqueakFFIPrims_exports[][3] = {
    {"SqueakFFIPrims", "ffiLogCallsTo", (void*)ffiLogCallsTo},
    {"SqueakFFIPrims", "getModuleName", (void*)getModuleName},
    {"SqueakFFIPrims", "initialiseModule", (void*)initialiseModule},
    {"SqueakFFIPrims", "primitiveCallout", (void*)primitiveCallout},
    {"SqueakFFIPrims", "primitiveCalloutWithArgs",
    {"SqueakFFIPrims", "primitiveFFIAllocate", (void*)primitiveFFIAllocate},
    {"SqueakFFIPrims", "primitiveFFIDoubleAt", (void*)primitiveFFIDoubleAt},
    {"SqueakFFIPrims", "primitiveFFIDoubleAtPut",
    {"SqueakFFIPrims", "primitiveFFIFloatAt", (void*)primitiveFFIFloatAt},
    {"SqueakFFIPrims", "primitiveFFIFloatAtPut",
    {"SqueakFFIPrims", "primitiveFFIFree", (void*)primitiveFFIFree},
    {"SqueakFFIPrims", "primitiveFFIGetLastError",
    {"SqueakFFIPrims", "primitiveFFIIntegerAt",
    {"SqueakFFIPrims", "primitiveFFIIntegerAtPut",
    {"SqueakFFIPrims", "primitiveForceLoad", (void*)primitiveForceLoad},
    {"SqueakFFIPrims", "primitiveLogCallsTo", (void*)primitiveLogCallsTo},
    {"SqueakFFIPrims", "setInterpreter", (void*)setInterpreter},

#endif /* ifdef SQ_BUILTIN_PLUGIN */

If primitiveCalloutWithArgs is missing then SqueakFFIPrims.c didn't get
generated correctly.  Go back to VMMaker and the FFIPlugin source and try to
figure out why.  Note that the table shouldn't be being used because the
plugin is typically used as an external plugin.  If you're building it in
then ignore what follows and reply saying "I want an internal plugin

If primitiveCalloutWithArgs isn't missing then is it being exported form the
module?  Use nm on whatever SqueakFFIPrims is compiled to and make sure its
exported.  It should have something like the following:

$ nm
| grep primitiveC
00004200 T _primitiveCallout
00003750 T _primitiveCalloutWithArgs

If there's a lowercase t there' figure out why it isn't being exported.
 e.g. EXPORT macro definition, linker commands, etc...

If it is being exported then you need to start
debugging ioLoadSymbolOfLengthFromModule, because that's failing to extract
the address of primitiveCalloutWithArgs from the loaded module.


> --
> Gary Dunn, Honolulu
> osp at aloha.com
> http://openslate.net/
> http://e9erust.blogspot.com/
> Sent from Slate001
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20091120/9cb921d0/attachment-0001.htm

More information about the Vm-dev mailing list