| 210 | }; |
| 211 | |
| 212 | void ThunkHandler_impl::LoadLib(std::string_view Name) { |
| 213 | auto SOName = ThunkHostLibsPath(); |
| 214 | while (SOName.ends_with('/')) { |
| 215 | SOName.pop_back(); |
| 216 | } |
| 217 | SOName = fmt::format("{}{}/{}-host.so", SOName, (Is64BitMode() ? "" : "_32"), Name); |
| 218 | |
| 219 | LogMan::Msg::DFmt("LoadLib: {} -> {}", Name, SOName); |
| 220 | |
| 221 | auto Handle = dlopen(SOName.c_str(), RTLD_LOCAL | RTLD_NOW); |
| 222 | if (!Handle) { |
| 223 | ERROR_AND_DIE_FMT("LoadLib: Failed to dlopen thunk library {}: {}", SOName, dlerror()); |
| 224 | } |
| 225 | |
| 226 | // Library names often include dashes, which may not be used in C++ identifiers. |
| 227 | // They are replaced with underscores hence. |
| 228 | auto InitSym = "fexthunks_exports_" + fextl::string {Name}; |
| 229 | std::replace(InitSym.begin(), InitSym.end(), '-', '_'); |
| 230 | |
| 231 | struct ExportEntry { |
| 232 | uint8_t* sha256; |
| 233 | FEXCore::ThunkedFunction* Fn; |
| 234 | }; |
| 235 | |
| 236 | ExportEntry* (*InitFN)(); |
| 237 | (void*&)InitFN = dlsym(Handle, InitSym.c_str()); |
| 238 | if (!InitFN) { |
| 239 | ERROR_AND_DIE_FMT("LoadLib: Failed to find export {}", InitSym); |
| 240 | } |
| 241 | |
| 242 | auto Exports = InitFN(); |
| 243 | if (!Exports) { |
| 244 | ERROR_AND_DIE_FMT("LoadLib: Failed to initialize thunk library {}. " |
| 245 | "Check if the corresponding host library is installed " |
| 246 | "or disable thunking of this library.", |
| 247 | Name); |
| 248 | } |
| 249 | |
| 250 | { |
| 251 | std::lock_guard lk(ThunksMutex); |
| 252 | |
| 253 | Libs.insert(fextl::string {Name}); |
| 254 | |
| 255 | int i; |
| 256 | for (i = 0; Exports[i].sha256; i++) { |
| 257 | Thunks[*reinterpret_cast<FEXCore::IR::SHA256Sum*>(Exports[i].sha256)] = Exports[i].Fn; |
| 258 | } |
| 259 | |
| 260 | LogMan::Msg::DFmt("Loaded {} syms", i); |
| 261 | } |
| 262 | } |
| 263 | |
| 264 | /** |
| 265 | * Generates a host-callable trampoline to call guest functions via the host ABI. |