SEGFAULT调用DLL函数

时间:2011-05-06 11:53:45

标签: c++ opencl

我目前正在尝试编辑已经使用OpenCL.dll的项目,以使其动态加载库。我希望能够在没有OpenCL系统的情况下使用它,只有一个错误信息和一个功能被禁用。

首先,我在函数中添加了一些包装器。 (此代码在C ++类中,并且是公共的)

    typedef cl_int h_clGetPlatformIDs(cl_uint, cl_platform_id *, cl_uint *);
    typedef cl_int h_clGetDeviceIDs(cl_platform_id, cl_device_type, cl_uint, cl_device_id *, cl_uint *);
    typedef cl_context h_clCreateContext(cl_context_properties *, cl_uint, const cl_device_id *, void *(const char *, const void *, size_t, void *), void *, cl_int *);
    typedef cl_command_queue h_clCreateCommandQueue(cl_context, cl_device_id, cl_command_queue_properties, cl_int *);
    typedef cl_program h_clCreateProgramWithSource(cl_context, cl_uint, const char **, const size_t *, cl_int *);
    typedef cl_int (CALLBACK h_clBuildProgram)(cl_program, cl_uint,const cl_device_id *, const char *, void (*)(cl_program, void * ), void * ) CL_API_SUFFIX__VERSION_1_0;
    typedef cl_int h_clGetProgramBuildInfo(cl_program, cl_device_id, cl_program_build_info, size_t, void  *, size_t  *);
    typedef cl_kernel h_clCreateKernel(cl_program, const char *, cl_int *);
    typedef cl_mem h_clCreateBuffer(cl_context, cl_mem_flags, size_t, void *, cl_int *);
    typedef cl_int h_clEnqueueWriteBuffer(cl_command_queue, cl_mem, cl_bool, size_t, size_t, const void *, cl_uint, const cl_event *, cl_event *);
    typedef cl_int h_clSetKernelArg(cl_kernel, cl_uint, size_t, const void *);
    typedef cl_int h_clEnqueueNDRangeKernel(cl_command_queue, cl_kernel, cl_uint, const size_t*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*);
    typedef cl_int h_clFlush(cl_command_queue);
    typedef cl_int h_clEnqueueReadBuffer(cl_command_queue, cl_mem, cl_bool, size_t, size_t, void *, cl_uint, const cl_event *, cl_event *);
    typedef cl_int h_clWaitForEvents(cl_uint, const cl_event *);
    typedef cl_int h_clReleaseMemObject(cl_mem );
    typedef cl_int h_clReleaseEvent(cl_event );
    typedef cl_int h_clReleaseProgram(cl_program );
    typedef cl_int h_clReleaseKernel(cl_kernel);
    typedef cl_int h_clReleaseCommandQueue(cl_command_queue );
    typedef cl_int h_clReleaseContext(cl_context );

    h_clGetPlatformIDs* clGetPlatformIDs;
    h_clGetDeviceIDs* clGetDeviceIDs;
    h_clCreateContext* clCreateContext;
    h_clCreateCommandQueue* clCreateCommandQueue;
    h_clCreateProgramWithSource* clCreateProgramWithSource;
    h_clBuildProgram* clBuildProgram;
    h_clGetProgramBuildInfo* clGetProgramBuildInfo;
    h_clCreateKernel* clCreateKernel;
    h_clCreateBuffer* clCreateBuffer;
    h_clEnqueueWriteBuffer* clEnqueueWriteBuffer;
    h_clSetKernelArg* clSetKernelArg;
    h_clEnqueueNDRangeKernel* clEnqueueNDRangeKernel;
    h_clFlush* clFlush;
    h_clEnqueueReadBuffer* clEnqueueReadBuffer;
    h_clWaitForEvents* clWaitForEvents;
    h_clReleaseMemObject* clReleaseMemObject;
    h_clReleaseEvent* clReleaseEvent;
    h_clReleaseProgram* clReleaseProgram;
    h_clReleaseKernel* clReleaseKernel;
    h_clReleaseCommandQueue* clReleaseCommandQueue;
    h_clReleaseContext* clReleaseContext;

有了这个,我可以直接为处理程序分配GetProcAdress返回的内容,之后只需调用该函数(当然,我首先加载DLL)。

    clReleaseContext = (h_clReleaseContext*) GetProcAddress(ocl_lib_handle, "clReleaseContext");

一个常见的电话示例:

clReleaseContext((cl_context)context);

但我总是让SEGFAULT称之为:

clBuildProgram(program, 0, NULL, "-cl-fast-relaxed-math", NULL, NULL);

这很奇怪,因为所有其他的都可以正常工作。 我在这里发布clBuildProgram Args作为参考:

    extern CL_API_ENTRY cl_int CL_API_CALL
clBuildProgram(cl_program           /* program */,
               cl_uint              /* num_devices */,
               const cl_device_id * /* device_list */,
               const char *         /* options */, 
               void (*pfn_notify)(cl_program /* program */, void * /* user_data */),
               void *               /* user_data */) CL_API_SUFFIX__VERSION_1_0;

谢谢!

4 个答案:

答案 0 :(得分:1)

您的typedef必须与OpenCL标题中的声明完全匹配。他们没有,你不使用CL_API_ENTRY,CL_API_CALL。我没有在第一个参数的原始声明中看到CALLBACK。

这当然是编写和维护的可怕代码。 clBuildProgram()函数有很多机会在没有你帮助的情况下轰炸访问冲突。首先使用测试程序将其抽出,使主代码正常运行。请求,窃取或借用以利用MSVC链接器的/ DELAYLOAD功能。

答案 1 :(得分:1)

每次调用GetProcAddress时,都应检查返回NULL,看看是否能够在DLL中找到该函数。

如果在尝试加载clBuildProgram时返回NULL,则函数名称查找出现问题。

如果它给你一个有效的指针,但是typedef与签名完全不匹配,那么你会将损坏的数据传递给函数,并可能崩溃。

如果你有一个有效的指针和一个正确的typedef,那么也许你只是传递不好的参数?我在0的调用中看到了很多NULLclBuildProgram - 也许这个错误在CL代码中?当你直接调用它时(即没有动态加载),你可以使用相同的参数调用clBuildProgram吗?

答案 2 :(得分:1)

一个可能的int:你在C和C ++中合并的API没有相同的ABI,从二进制文件中传递参数是不同的(这就是为什么在C ++中使用C时,你需要使用

extern "C" {
  #include "c_api.h"
}

你应该围绕这个主题进行谷歌搜索,看看如何使用C调用约定/修改来强制调用处理程序。不确定这是解决方案,但它绝对值得研究,因为它会导致这个确切的结果。

答案 3 :(得分:0)

我不知道究竟解决了什么问题。 我重写了.h文件,其中包含一个带有__stdcall添加的OpenCL文件的typedef副本。 然后使用extern“C”。

正在工作!!

谢谢大家!