Dave Korn wrote: > Yep, that's more-or-less what I was referring to by "stunk thubbery" ;-)
With one important difference: the plan you outlined relies on the .exe exporting the function that overrides the copy in the dll. This is somewhat controversial (IMHO) in that it requires adorning the function with __declspec(dllexport) (or -Wl,--export-all-symbols or using a .def file) and it is not typical to export from an executable. If at all possible I'd like to avoid this. The current special casing for malloc/free doesn't require exporting, because the names of the overriding symbols are available to the linker at the time the executable is linked (i.e. the statically linked crt startup code), and so it can choose at that time which copy to resolve. The problem with this is that, contrary to what I outlined previously, it cannot be done dynamically; the linker must see a reference to the symbol, i.e. "foo = &malloc;". But this can be solved as you hinted by adding a static stub to the import library. The issue about breaking direct-to-DLL linking is not a problem in my opinion, because in the Cygwin distro we always use import libraries because they provide the "ABI name indirection" that lets e.g. -lintl link to cygintl-8.dll without having to specify it as -lintl-8. There are other situations where an import library is required, such as when you are trying to link to stdcall calling convention functions that aren't decorated. So this would just be another case where using an import library is required, and it would be of essentially zero burden to the distro as it exists today because we always ship and import lib anyway. So, we teach the linker that when creating an import library for a DLL, if it sees a weak function exported it should emit a small static stub in the import library that takes the address of that function. We can add a runtime support function to receive that address, let's call it _pei386_add_overridable() just for the sake of argument. It could be a static CRT function like the runtime pseudo reloc helper function _pei386_runtime_relocator() which also gets statically linked into every app, or it could be in libgcc, or Cygwin. I'd prefer the static CRT option, just because it is universal, standalone, and safe; and there's a precedent for doing it that way with the runtime pseudo reloc helper. The downside of this is that it will require apps to be linked with a newer (presumbaly 1.7 only) version of Cygwin to pick up the new libcygwin.a which contains these static bits. Anyway, so the linker puts a stub that looks like this in the import library of the DLL it is linking: _pei386_weakhelper_<uniquestring>() { _pei386_add_overridable ("malloc", &malloc); } Where malloc is the symbol that was marked weak in the DLL it's linking. The <uniquestring> is just something to make sure no two of these collide but is also unique in that it can be keyed to the function name. Maybe it's just the function name alone, I dunno. Next we need something to cause these stubs to get included into the link when linking an executable against such an import library. So we make the linker keep a running tab of symbols in the executable that it has resolved with an import library for which there exists a _pei386_weakhelper_<uniquestring>() stub for that symbol. At the end of the link it synthesizes a function that calls each of the stubs, and adds that synthetic object into the link: _pei386_weakhelper() { _pei386_weakhelper_for_sym1(); _pei386_weakhelper_for_sym2(); ... } Next we add a call to _pei386_weakhelper() in the Cygwin CRT startup so that that synthetic object and all stubs get pulled into the final link. We also write an implementation of _pei386_add_overridable() that just maintains a list of pairs of (function name, pointer). At this point we have achieved the feat that we have at runtime a dynamic list of all overridable functions by name and pointer, without ever touching the export tables or requiring they be exported at all. The other half of this version of the plan would be identical to yours, i.e. add indirection on the DLL side to get the function's address at runtime. Preferably this would be in a sort of PLT-like manner where the overhead of looking up a symbol's address by name only happens the first time and thereafter it's just an indirect jump through a slot. Brian -- Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple Problem reports: http://cygwin.com/problems.html Documentation: http://cygwin.com/docs.html FAQ: http://cygwin.com/faq/