DFHack / dfhack

Memory hacking library for Dwarf Fortress and a set of tools that use it
Other
1.84k stars 463 forks source link

add symbol lookup functions for dfsdl and dfimg #4757

Open dhthwy opened 3 days ago

dhthwy commented 3 days ago

I want something like this.

myk002 commented 3 days ago

do you actually need the address of the function instead of an API to call through to that function (the pattern for all the existing DFSDL functions)?

dhthwy commented 3 days ago

I don't know how many I will ultimately need and the list may change:

int Console_Init(void* (*sdl_resolver)(const char*), img_resolver...)
{
      resolve_sdl_symbols(sdl_resolver);
      ...
}

#if defined(CONSOLE_SDL_LINK_AT_RUNTIME) && (CONSOLE_SDL_LINK_AT_RUNTIME) == 1
#define CONSOLE_SYMBOL_ADDR(sym) nullptr
#else
#define CONSOLE_SYMBOL_ADDR(sym) ::sym
#endif

#define CONSOLE_DEFINE_SYMBOL(sym) decltype(sym)* sym = CONSOLE_SYMBOL_ADDR(sym)

CONSOLE_DEFINE_SYMBOL(SDL_ConvertSurfaceFormat);
CONSOLE_DEFINE_SYMBOL(SDL_CreateRenderer);
CONSOLE_DEFINE_SYMBOL(SDL_CreateRGBSurface);
CONSOLE_DEFINE_SYMBOL(SDL_CreateTexture);
CONSOLE_DEFINE_SYMBOL(SDL_CreateTextureFromSurface);
CONSOLE_DEFINE_SYMBOL(SDL_CreateWindow);
CONSOLE_DEFINE_SYMBOL(SDL_DestroyRenderer);
CONSOLE_DEFINE_SYMBOL(SDL_DestroyTexture);
CONSOLE_DEFINE_SYMBOL(SDL_DestroyWindow);
CONSOLE_DEFINE_SYMBOL(SDL_free);
CONSOLE_DEFINE_SYMBOL(SDL_GetClipboardText);
CONSOLE_DEFINE_SYMBOL(SDL_GetError);
CONSOLE_DEFINE_SYMBOL(SDL_GetEventFilter);
CONSOLE_DEFINE_SYMBOL(SDL_GetModState);
CONSOLE_DEFINE_SYMBOL(SDL_GetRendererOutputSize);
CONSOLE_DEFINE_SYMBOL(SDL_GetWindowFlags);
CONSOLE_DEFINE_SYMBOL(SDL_GetWindowID);
CONSOLE_DEFINE_SYMBOL(SDL_HideWindow);
CONSOLE_DEFINE_SYMBOL(SDL_iconv_string);
CONSOLE_DEFINE_SYMBOL(SDL_InitSubSystem);
CONSOLE_DEFINE_SYMBOL(SDL_MapRGB);
CONSOLE_DEFINE_SYMBOL(SDL_memset);
CONSOLE_DEFINE_SYMBOL(SDL_RenderClear);
CONSOLE_DEFINE_SYMBOL(SDL_RenderCopy);
CONSOLE_DEFINE_SYMBOL(SDL_RenderDrawRect);
CONSOLE_DEFINE_SYMBOL(SDL_RenderFillRect);
CONSOLE_DEFINE_SYMBOL(SDL_RenderPresent);
CONSOLE_DEFINE_SYMBOL(SDL_RenderSetIntegerScale);
CONSOLE_DEFINE_SYMBOL(SDL_RenderSetViewport);
/* CONSOLE_DEFINE_SYMBOL(SDL_PointInRect); inline defined in SDL_rect.h header */ 
CONSOLE_DEFINE_SYMBOL(SDL_SetClipboardText);
CONSOLE_DEFINE_SYMBOL(SDL_SetColorKey);
CONSOLE_DEFINE_SYMBOL(SDL_SetEventFilter);
CONSOLE_DEFINE_SYMBOL(SDL_SetHint);
CONSOLE_DEFINE_SYMBOL(SDL_SetRenderDrawColor);
CONSOLE_DEFINE_SYMBOL(SDL_SetTextureBlendMode);
CONSOLE_DEFINE_SYMBOL(SDL_SetTextureColorMod);
CONSOLE_DEFINE_SYMBOL(SDL_SetWindowMinimumSize);
CONSOLE_DEFINE_SYMBOL(SDL_ShowWindow);
CONSOLE_DEFINE_SYMBOL(SDL_StartTextInput);
CONSOLE_DEFINE_SYMBOL(SDL_StopTextInput);
CONSOLE_DEFINE_SYMBOL(SDL_UpperBlit);
CONSOLE_DEFINE_SYMBOL(SDL_UpdateTexture);
CONSOLE_DEFINE_SYMBOL(SDL_QuitSubSystem);
myk002 commented 3 days ago

it's fine to extend the DFSDL API as needed. you might want to refactor to reduce the boilerplate if you'll be adding so many functions, though.

lethosor commented 3 days ago

I'm not opposed to adding something like this for development/debugging purposes, but any code we integrate should call out to "proper" functions defined in DFSDL so that future code can benefit from having those functions available.

dhthwy commented 3 days ago

I don't object to adding these to DFSDL. I guess my only concern would be it might eventually include all SDL functions if there's plugins, etc making lots of use of SDL.

dhthwy commented 2 days ago

Do we want DFSDL init() to resolve all SDL functions on startup, including dozens that some component may or not use?

What if we did late binding for the functions that aren't common and not used in core?

DFSDL::Uncommon(int x) {
    if (!g_SDL_Uncommon) {
        // lookup and bind
    }
    return ...
}
myk002 commented 2 days ago

is there any significant resource usage or time penalty? linking symbols should be pretty fast

dhthwy commented 2 days ago

Storage should already be allocated, right? A few dozen pointers worth. I'd say no on resource usage.

Time to call a few dozen symbol lookups... probably still in the nanoseconds on any modern puter. dlsym and GetProcAddress should be highly optimized. Probably not worth benching.

lethosor commented 2 days ago

Binding everything at init time is almost certainly faster than checking if binding is necessary at call time (i.e. the late bindings you proposed), at least beyond a certain number of calls.

dlsym() is not particularly fast. Maybe microseconds, maybe closer to milliseconds with our number of calls.

I think the main reason we don't just "bind everything" is the number of stubs that would have to be written manually. C barely offers any way to programmatically generate these stubs; the closest approaches I've seen involve defining function prototypes with macros which can be redefined to process each function in other ways, but the SDL headers aren't defined in that way. C++ will get us closer, but there's still a fair amount of manual effort.