[RFC PATCH 0/5] XAudio PE conversion.

Zebediah Figura zfigura at codeweavers.com
Wed Sep 8 23:38:49 CDT 2021


On 9/3/21 2:11 PM, Zebediah Figura (she/her) wrote:
> 
> 
> On 9/3/21 12:02 PM, Alexandre Julliard wrote:
>> "Zebediah Figura (she/her)" <zfigura at codeweavers.com> writes:
>>
>>> On 9/3/21 3:26 AM, Alexandre Julliard wrote:
>>>> "Zebediah Figura (she/her)" <zfigura at codeweavers.com> writes:
>>>>
>>>>> Actually, an alternate solution occurred to me:
>>>>>
>>>>> If we are loading any library that is a dependency of a builtin
>>>>> library, always load it from a fixed path like /usr/lib/wine/ext/, and
>>>>> essentially treat it as if we had loaded using an absolute path
>>>>> instead of a relative path, so as to skip existing DLLs loaded under
>>>>> that name.
>>>>>
>>>>> Mark that DLL with an internal flag, and don't consider it when
>>>>> searching for existing DLLs with that name, to avoid the other side.
>>>>>
>>>>> I know there are a lot of other things standing in the way of shared
>>>>> libraries, and that this would require some nontrivial loader work,
>>>>> but does it at least seem plausible? Are there snags I'm not noticing?
>>>> Sure, you can try to create a separate namespace for these without
>>>> actually changing their names. It's not clear to me how you are going to
>>>> determine which DLLs should go into that namespace, and how that's going
>>>> to work with apps that do import resolving by hand.
>>>> You'll also have to invent some mechanism to have Wine treat them as
>>>> builtins even though they don't have the builtin flag.
>>>
>>> The distinguishing factor I was thinking of is that if it's a system
>>> lib or linked to by a system lib, it's marked as a system lib. That
>>> doesn't work for libraries loaded dynamically, and there we have the
>>> extra caveat that we don't want to mark every dynamically loaded
>>> library as a system lib, so I think we'd need an internal flag to
>>> LoadLibraryExW().
>>
>> I don't see how this would work. All such libraries will import msvcrt
>> or kernel32, but you can't have these end up in a separate namespace.
>>
>> And how do you define a "system lib"? Do you somehow tell the PE loader
>> the actual Unix path that the dll was loaded from?  What if the distro
>> installs the Wine DLLs in the same dir?
>>
>>>> And somehow you
>>>> need to differentiate them from the exact same DLLs being shipped by an
>>>> app...
>>>
>>> Sorry, I'm not sure what you mean by this, that's different from what
>>> I described above?
>>
>> Well, you'll need to copy, say, zlib1.dll into the prefix. How do you
>> know this is the zlib1.dll from the system package, and not one
>> installed by an app?  Do you add the builtin flag, altering the binary
>> when copying it?
>>
> 
> I did fail to consider that case, thanks.
> 
> After thinking about it for a while I've come up with the following
> algorithm:
> 
> Suppose that module A imports module B.
> 
> 1. If module A is marked "builtin" or "system":
> 
>       a. Try to find a module marked "builtin" or "system" in memory, and
> return it if found. (Skip "builtin" if the load order requires.)
> 
>       b. Try to load a module from WINESYSTEMDLLDIR#. If found, mark the
> module as "system".
> 
>       c. Try to find a module marked "native" in memory, and return it if
> found. (Skip this step if the load order requires.)
> 
>       d. Try to load a builtin or native module using the normal logic.
> 
> 2. Otherwise, i.e. module A is native:
> 
>       a. Try to find a module marked "builtin" or "native" (modulo load
> order) in memory, and return it if found. Skip "system".
> 
>       b. Try to load a builtin or native module using the normal logic.
> 
> 
> This should avoid ever loading a system module for a native module; it
> should avoid loading a native module when we want a system module
> (provided that system modules are present; if they aren't things are
> already broken). It should also handle e.g. ucrtbase imports, regardless
> if ucrtbase is builtin or native.
> 
> The downside I can see is that if ucrtbase is native, we'll always
> search WINESYSTEMDLLDIRs for it. If that's a performance problem, we
> could always bypass step 1b for a predefined list of modules.
> 
> This does rely on the fact that WINESYSTEMDLLDIRs are unique and only
> contain system libraries. It's not obvious to me that would be a problem
> to guarantee. The list might contain one or more paths like:
> 
> * C:/windows/system32/wine-ext/ [1]
> * Z:/usr/x86_64-w64-mingw32/bin/ [2]
> * Z:/usr/lib/wine/ext/
> 
> I'm sure this all looks like a pile of hacks. Granted, it doesn't look
> unreasonable to me, but I suppose I'm also biased. I'm just trying my
> best to make dynamic libraries a possibility, because static libraries
> suck for development. And, more importantly, I'm trying to give
> distributions an accurate representation of our requirements.
> 
> 
> [1] As far as I'm aware, the only reason we need to copy libraries to
> the C: drive is that anticheats *might* complain if libraries are loaded
> from another drive? Was there a concrete example of this? Or was there
> another problem I was missing?
> 
> [2] Or distribution equivalent. That's assuming that distributions are
> in favor of having us dynamically link to pre-built libraries, though,
> and that's an open question. It's also not clear how we would get this path.
> 

Actually, while thinking about it I realized another, more salient snag: 
if system library A tries to load system library B dynamically, we have 
no way of knowing whether to give it the system or application library.

I don't think there's any way around this. Even rewriting the import 
table using objcopy or something (which was actually proposed in 
conversation with distributions) wouldn't fix this. We have to use a 
different name, or abandon dynamic libraries altogether.

Maybe there's clever solution I'm missing?



More information about the wine-devel mailing list