Fix(sim): pass context helpers to AICore SO instead of dlsym(RTLD_DEFAULT)#451
Fix(sim): pass context helpers to AICore SO instead of dlsym(RTLD_DEFAULT)#451hw-native-sys-bot wants to merge 1 commit intohw-native-sys:mainfrom
Conversation
…AULT) The AICore kernel SO used dlsym(RTLD_DEFAULT, "pto_cpu_sim_*") to resolve sim context functions. This fails when libhost_runtime.so is loaded with RTLD_LOCAL, which is needed for multi-runtime in-process isolation. Replace with explicit function pointer injection via set_sim_context_helpers. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request refactors the simulation context bridging between the AICore kernel and host runtime for the a2a3 and a5 platforms. By replacing dlsym(RTLD_DEFAULT) with an explicit function pointer registration mechanism (set_sim_context_helpers), the implementation avoids resolution failures when the host library is loaded with RTLD_LOCAL. The review feedback recommends enhancing the robustness of symbol resolution in DeviceRunner by using dlerror() to check for errors after calling dlsym and ensuring proper error reporting.
| auto set_helpers = | ||
| reinterpret_cast<void (*)(void *, void *, void *)>(dlsym(aicore_so_handle_, "set_sim_context_helpers")); | ||
| if (set_helpers != nullptr) { | ||
| set_helpers( | ||
| reinterpret_cast<void *>(pto_cpu_sim_set_execution_context), | ||
| reinterpret_cast<void *>(pto_cpu_sim_set_task_cookie), | ||
| reinterpret_cast<void *>(platform_get_cpu_sim_task_cookie) | ||
| ); | ||
| } |
There was a problem hiding this comment.
To robustly check for errors with dlsym, call dlerror() to clear any prior errors before the call, and then check the result of dlerror() afterwards. Additionally, ensure that resource cleanup (like dlclose) is handled if initialization fails to prevent leaks.
| auto set_helpers = | |
| reinterpret_cast<void (*)(void *, void *, void *)>(dlsym(aicore_so_handle_, "set_sim_context_helpers")); | |
| if (set_helpers != nullptr) { | |
| set_helpers( | |
| reinterpret_cast<void *>(pto_cpu_sim_set_execution_context), | |
| reinterpret_cast<void *>(pto_cpu_sim_set_task_cookie), | |
| reinterpret_cast<void *>(platform_get_cpu_sim_task_cookie) | |
| ); | |
| } | |
| (void)dlerror(); | |
| auto set_helpers = reinterpret_cast<void (*)(void *, void *, void *)>(dlsym(aicore_so_handle_, "set_sim_context_helpers")); | |
| const char *dlsym_err = dlerror(); | |
| if (dlsym_err != nullptr) { | |
| LOG_ERROR("dlsym failed for set_sim_context_helpers: %s", dlsym_err); | |
| return -1; | |
| } | |
| set_helpers(reinterpret_cast<void *>(pto_cpu_sim_set_execution_context), reinterpret_cast<void *>(pto_cpu_sim_set_task_cookie), | |
| reinterpret_cast<void *>(platform_get_cpu_sim_task_cookie)); |
References
- To robustly check for errors with dlsym, call dlerror() to clear any prior errors, then call dlsym, and then check the result of dlerror() to see if an error occurred.
- To prevent resource leaks with handles acquired via dlopen, use a try-catch block to ensure dlclose is called if any subsequent initialization steps fail.
| auto set_helpers = | ||
| reinterpret_cast<void (*)(void *, void *, void *)>(dlsym(aicore_so_handle_, "set_sim_context_helpers")); | ||
| if (set_helpers != nullptr) { | ||
| set_helpers( | ||
| reinterpret_cast<void *>(pto_cpu_sim_set_execution_context), | ||
| reinterpret_cast<void *>(pto_cpu_sim_set_task_cookie), | ||
| reinterpret_cast<void *>(platform_get_cpu_sim_task_cookie) | ||
| ); | ||
| } |
There was a problem hiding this comment.
To robustly check for errors with dlsym, call dlerror() to clear any prior errors before the call, and then check the result of dlerror() afterwards. Additionally, ensure that resource cleanup (like dlclose) is handled if initialization fails to prevent leaks.
| auto set_helpers = | |
| reinterpret_cast<void (*)(void *, void *, void *)>(dlsym(aicore_so_handle_, "set_sim_context_helpers")); | |
| if (set_helpers != nullptr) { | |
| set_helpers( | |
| reinterpret_cast<void *>(pto_cpu_sim_set_execution_context), | |
| reinterpret_cast<void *>(pto_cpu_sim_set_task_cookie), | |
| reinterpret_cast<void *>(platform_get_cpu_sim_task_cookie) | |
| ); | |
| } | |
| (void)dlerror(); | |
| auto set_helpers = reinterpret_cast<void (*)(void *, void *, void *)>(dlsym(aicore_so_handle_, "set_sim_context_helpers")); | |
| const char *dlsym_err = dlerror(); | |
| if (dlsym_err != nullptr) { | |
| LOG_ERROR("dlsym failed for set_sim_context_helpers: %s", dlsym_err); | |
| return -1; | |
| } | |
| set_helpers(reinterpret_cast<void *>(pto_cpu_sim_set_execution_context), reinterpret_cast<void *>(pto_cpu_sim_set_task_cookie), | |
| reinterpret_cast<void *>(platform_get_cpu_sim_task_cookie)); |
References
- To robustly check for errors with dlsym, call dlerror() to clear any prior errors, then call dlsym, and then check the result of dlerror() to see if an error occurred.
- To prevent resource leaks with handles acquired via dlopen, use a try-catch block to ensure dlclose is called if any subsequent initialization steps fail.
Summary
The AICore kernel SO used
dlsym(RTLD_DEFAULT, "pto_cpu_sim_*")to resolve sim context functions defined incpu_sim_context.cpp. This works withRTLD_GLOBALbut fails withRTLD_LOCAL— the symbols are not in the global table, sodlsym(RTLD_DEFAULT)returns NULL.This is a prerequisite for loading
libhost_runtime.sowithRTLD_LOCAL(needed when multiple runtimes coexist in the same process without symbol pollution).Fix: Replace
dlsym(RTLD_DEFAULT)with explicit function pointer injection:kernel.cpp(a2a3 + a5): addset_sim_context_helpers()extern-C entry point, stores 3 function pointersinner_kernel.h(a2a3 + a5): use stored pointers instead ofstatic auto fn = dlsym(RTLD_DEFAULT, ...)device_runner.cpp(a2a3 + a5): callset_sim_context_helpers()after loading AICore SOcpu_sim_context.h(a2a3 + a5): declare the extern-C context functions for device_runnerNo behavioral change with current
RTLD_GLOBALloading — the function pointers are resolved at the same time (AICore SO load) and point to the same functions.Testing
python ci.py -p a2a3sim -c 6622890 -t 600— 20/20 PASS