[RFC PATCH 0/5] XAudio PE conversion.

Gabriel Ivăncescu gabrielopcode at gmail.com
Thu Sep 9 08:33:44 CDT 2021


On 09/09/2021 07:38, Zebediah Figura wrote:
> 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?
> 

Can't you just add some wine-specific logic to LoadLibrary to handle 
this? System libs shouldn't be loading non-system-libs anyway. While it 
may be ugly, you can check the return address and see if it's within a 
system lib's address range.



More information about the wine-devel mailing list