调用 DLL 函数的 SEGFAULT
SEGFAULT calling DLL functions
我目前正在尝试编辑一个已经使用 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;
谢谢!
您的 typedef 必须与 OpenCL 标头中的声明完全匹配。 他们没有,你不使用CL_API_ENTRY,CL_API_CALL。 我在第一个参数的原始声明中没有看到回调。
这当然是编写和维护的可怕代码。 否则,clBuildProgram() 函数有很多机会在没有您帮助的情况下轰炸访问违规。 首先用一个测试程序来消除它,让你的主代码正常运行。 乞求、偷窃或借用以利用 MSVC 链接器的/DELAYLOAD 功能。
每次调用GetProcAddress
时,都应检查 NULL 的返回值,以查看是否能够在 DLL 中找到该函数。
如果在尝试加载 clBuildProgram 时返回 NULL,则函数名称查找有问题。
如果它为您提供了一个有效的指针,但 typedef 与签名不完全匹配,那么您会将损坏的数据传递给函数,并可能崩溃。
如果你有一个有效的指针和一个正确的 typedef,那么也许你只是在传递糟糕的参数? 我在您对clBuildProgram
的调用中看到了很多0
和NULL
- 也许错误在 CL 代码中? 当您直接调用它时(即没有动态加载),您可以使用相同的参数调用clBuildProgram
吗?
一个可能的 int :您正在合并 C 和 C++ 中没有相同 ABI 的 API,从二进制传递参数是不同的(这就是为什么在 C++ 中使用 C 时,您需要使用
extern "C" {
#include "c_api.h"
}
你应该谷歌一下这个主题,看看如何使用 C 调用约定/重整强制调用你的处理程序。不确定这是解决方案,但绝对值得调查,因为它会导致这个确切的结果。
是什么解决了这个问题。我用 OpenCL 文件的 typedefs 副本重写了一个 .h 文件,并添加了 __stdcall。然后使用外部"C"。
并且正在工作!!
谢谢大家!
- SegFault 同时使用 std::string::operator+= 和函数作为参数
- 导致SegFault C++的析构函数
- 将数组传递给C 函数时,segfault
- 用于评估导致Segfault的Postfix的函数
- SegFault将插入std :: vector的成员函数插入std :: vector
- 类析构函数 SEGFAULT
- std::函数析构函数中的Segfault
- 在函数结束后仅释放 Segfault 与 vsnprintf 一起消失
- 主函数执行之前的C++segfault
- 调用一些PyObject函数会导致segfault-Boost python
- 在构造函数中使用curl_easy_init会导致segfault
- 析构函数上的Segfault
- 通过多个函数传递指针并获取segfault
- v8在Windows上的HandleScope构造函数中的SegFault
- 在析构函数中释放内存时出现segfault
- 调用结构的虚函数时出现segfault
- 将矢量指针传递给函数会导致segfault
- 当类被创建为shared_ptr时,添加到类中的其他函数会导致segfault
- 为什么我的合并函数会给我一个segfault
- 调用 DLL 函数的 SEGFAULT