<div dir="auto">Very nice sum up of the whole situation. Sounds perfect for the wiki.<div dir="auto"><br></div><div dir="auto">Bernhard </div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Eric Pouech <<a href="mailto:eric.pouech@orange.fr">eric.pouech@orange.fr</a>> schrieb am Do., 14. Apr. 2022, 17:26:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
  

    
  
  <div>
    <p><font face="Helvetica, Arial, sans-serif">I tried to write down
        what I grasped for the current modules' evolution</font></p>
    <p><font face="Helvetica, Arial, sans-serif">since there's always
        questions floating around this subject, might be worthwhile to
        document it a bit</font></p>
    <p><font face="Helvetica, Arial, sans-serif">it's likely full of
        errors, shortcuts, misconceptions... so don't hesitate to
        comment/amend</font></p>
    <p><font face="Helvetica, Arial, sans-serif"><br>
      </font></p>
    <p><font face="monospace">Wine "old" module model:<br>
        -----------------------<br>
        Wine used to generate a module (DLL or EXE) as:<br>
        - an .so (ELF) module, compiled with a native compiler<br>
        - this .so module embeds also PE module information, so that
        Wine's loader<br>
          exposes to Windows application the PE module only.<br>
        <br>
          +--------------------------+<br>
          | <a href="http://FOOBAR.dll.so" target="_blank" rel="noreferrer">FOOBAR.dll.so</a> (ELF)      |<br>
          | +----------------------+ |<br>
          | | PE information       | |<br>
          | +----------------------+ |<br>
          +--------------------------+<br>
        <br>
        Wine loader is also able to load "pure" PE modules from
        .dll/.exe files.<br>
        <br>
        A built-in module (<a href="http://FOOBAR.dll.so" target="_blank" rel="noreferrer">FOOBAR.dll.so</a>) can use standard ELF dynamic
        linking to load<br>
        also ELF libraries (eg winepulse needs to loads libpulse.so).
        This is needed to<br>
        implement in Wine most of the integration into the Unix world;
        e.g: graphical<br>
        (X11 or image coding/decoding jpeg...), audio/video (pulse,
        gstreamer), and<br>
        other utilities (xml/xslt, database connectivity...) to name a
        few.<br>
        <br>
          +--------------------------+                +-----------+<br>
          | <a href="http://FOOBAR.dll.so" target="_blank" rel="noreferrer">FOOBAR.dll.so</a> (ELF)      | -------------> | helper.so |<br>
          | +----------------------+ | ELF dyn link   +-----------+<br>
          | | PE information       | |<br>
          | +----------------------+ |<br>
          +--------------------------+<br>
        <br>
        But, this had some limitations: some applications (version
        checking,<br>
        anti-crack...) were trying to open directly the FOOBAR.dll file
        (as it exists on<br>
        Windows) to read some elements inside. Wine implemented "fake"
        files to mimic<br>
        that PE file content.<br>
        <br>
          +--------------------------+                +-----------+<br>
          | <a href="http://FOOBAR.dll.so" target="_blank" rel="noreferrer">FOOBAR.dll.so</a> (ELF)      | -------------> | helper.so |<br>
          | +----------------------+ | ELF dyn link   +-----------+<br>
          | | PE information       | |<br>
          | +----------------------+ |<br>
          +--------------------------+<br>
        <br>
          +--------------------------+<br>
          | FOOBAR.dll (Fake PE)     |<br>
          +--------------------------+<br>
        <br>
        But this doesn't take into account 32 vs 64 bit applications
        (letting aside the<br>
        16bit part). So in fact, the global picture is closer to this:<br>
        <br>
          +------------------------------+                +-----------+<br>
          | <a href="http://FOOBAR.dll.so" target="_blank" rel="noreferrer">FOOBAR.dll.so</a> (ELF 64bit)    | -------------> | helper.so
        |<br>
          |  +------------------------+  | ELF dyn link   | (64 bit)  |<br>
          |  | PE information (64bit) |  |                +-----------+<br>
          |  +------------------------+  |<br>
          +------------------------------+<br>
        <br>
          +------------------------------+<br>
          | FOOBAR.dll (Fake 64 bit PE)  |<br>
          +------------------------------+<br>
        <br>
          +------------------------------+                +-----------+<br>
          | <a href="http://FOOBAR.dll.so" target="_blank" rel="noreferrer">FOOBAR.dll.so</a> (ELF 32bit)    | -------------> | helper.so
        |<br>
          |  +------------------------+  | ELF dyn link   | (32 bit)  |<br>
          |  | PE information (32bit) |  |                +-----------+<br>
          |  +------------------------+  |<br>
          +------------------------------+<br>
        <br>
          +------------------------------+<br>
          | FOOBAR.dll (Fake 32 bit PE)  |<br>
          +------------------------------+<br>
        <br>
        This requires that both 32 and 64bit .so libraries to be
        installed on the host.<br>
        <br>
        But again, this started to show some limitations:<br>
        - some Linux distros and Apple are willing to drop the 32bit
        support from their<br>
          packages, so the 32 bit helper.so libraries might not be
        available in the<br>
          future<br>
        - Apple evolution to support M1 family chip also adds another
        dimension to the<br>
          above picture (as a an application can either be compiled for
        ARM/M1 or Intel<br>
          chip, so there's also a need to support invocation from both
        processors (the<br>
          ABI is different, to start with).<br>
        <br>
        Wine "new" PE model: (PE migration...)<br>
        -------------------<br>
        In this model, Wine requires a cross-compiler to generate
        directly a PE file for<br>
        each module.<br>
        <br>
          +-----------------+<br>
          | FOOBAR.dll (PE) |<br>
          +-----------------+<br>
        <br>
        One of interesting benefit of this choice, is that the PE module
        can now simply<br>
        link with Window's libc implementation (either msvcrt or ucrt).
        In the "old"<br>
        model, the default was to use the unix libc libraries, yet
        providing some other<br>
        potential differences.<br>
        <br>
        For modules not requiring system .so files, this migration is
        rather<br>
        simple. There are still some elements to look at [1]. But most
        of the hard job<br>
        is done by the compiler and the Wine infrastructure.<br>
        <br>
        For modules requiring linking to .so files, the scheme has to be
        extended by<br>
        generating an additional ELF library, tied to the PE module.<br>
          +-----------------+          
        +-----------------+                +-----------+<br>
          | FOOBAR.dll (PE) |           | FOOBAR.so (ELF) |
        -------------> | helper.so |<br>
          |                 | --------> | (unixlib)       | ELF dyn
        link   +-----------+<br>
          |                 |           |                 |<br>
          +-----------------+           +-----------------+<br>
        <br>
        Addind this extra module in the middle allows to:<br>
        - do the translation from a entities defined in PE world into
        entities<br>
          defined in the ELF world (ABI are different, structures layout
        are different)<br>
        - this provides an abstraction of the library for the PE world.<br>
        - decide what to migrate from the existing code into the PE part
        (remember<br>
          existing library in old model lives in the ELF world)<br>
        <br>
        One can see the FOOBAR.so like a Wine-"system driver" for
        providing the required<br>
        support from the host.<br>
        <br>
        But, it brings constraints too. The ELF part cannot call back
        into the PE part<br>
        of the module, nor into other PE modules.<br>
        If this ELF parts requires some Wine "kernel features", the it
        can (using ELF<br>
        dynamic linking) use the APIs provided by ntdll.so ELF library.<br>
        <br>
          +-----------------+          
        +-----------------+                +-----------+<br>
          | FOOBAR.dll (PE) |           | FOOBAR.so (ELF) |
        -------------> | ntdll.so  |<br>
          |                 | --------> | (unixlib)       | ELF dyn
        link   +-----------+<br>
          |                 |           |                 |
        -------------> | helper.so |<br>
          +-----------------+          
        +-----------------+                +-----------+<br>
        <br>
        Note: likely some other modules .so should be available too
        (like win32u) (to be<br>
        confirmed)<br>
        <br>
        Currently, the 32 <> 64 bit is still duplicated:<br>
        <br>
          +-----------------+          
        +------------------------+                +--------------------+<br>
          | FOOBAR.dll (PE) |           | FOOBAR.so (ELF 64 bit) |
        -------------> | ntdll.so (64 bit)  |<br>
          | 64 bit          | --------> | (unixlib 64 bit)       |
        ELF dyn link   +--------------------+<br>
          |                 |           |                        |
        -------------> | helper.so (64 bit) |<br>
          +-----------------+          
        +------------------------+                +--------------------+<br>
        <br>
          +-----------------+          
        +------------------------+                +--------------------+<br>
          | FOOBAR.dll (PE) |           | FOOBAR.so (ELF 32 bit) |
        -------------> | ntdll.so (32 bit)  |<br>
          | 32 bit          | --------> | (unixlib 32 bit)       |
        ELF dyn link   +--------------------+<br>
          |                 |           |                        |
        -------------> | helper.so (32 bit) |<br>
          +-----------------+          
        +------------------------+                +--------------------+<br>
        <br>
        When all modules are converted to the new scheme, this shall
        look like:<br>
        <br>
          +-----------------+          
        +------------------------+                +--------------------+<br>
          | FOOBAR.dll (PE) |           | FOOBAR.so (ELF 64 bit) |
        -------------> | ntdll.so (64 bit)  |<br>
          | 64 bit          | --------> | (unixlib    )          |
        ELF dyn link   +--------------------+<br>
          |                 |    +----> | (64 + 32 bit)          |
        -------------> | helper.so (64 bit) |<br>
          +-----------------+    |     
        +------------------------+                +--------------------+<br>
                                 |<br>
          +-----------------+    |<br>
          | FOOBAR.dll (PE) |    |<br>
          | 32 bit          | ---+<br>
          |                 |<br>
          +-----------------+<br>
        <br>
        This will require that FOOBAR.so correctly handles the "syscall"
        for both 32 bit<br>
        and 64 bit unixlib calls.<br>
        When this is in place, no support for 32-bit .so files will be
        necessary (both<br>
        the packages that provide the .so files, but also for the
        development packages.<br>
        <br>
        Unixlib in a nutshell<br>
        ---------------------<br>
        A unixlib interface is just a table of entry points. Both ends
        (calling PE<br>
        side, and callee on ELF side) share:<br>
        - the semantic attached to an entry point a given index in the
        table<br>
          (usually defined as a value inside an enum)<br>
        - the signature of each entry point is always the same:<br>
          NTSTATUS the_func(void *args);<br>
        - args is a pointer to a structure containing input and output<br>
          parameters to this very entry point.<br>
          There's a specific structure for each function (in some rare
        cases, several<br>
          functions can use the same structure).<br>
        <br>
        Invoking on PE side looks like:<br>
        |  struct xxx_yyy arg;<br>
        |  /* fill in arg */<br>
        |  NTSTATUS status = __wine_unixlib_callinto(foobar.so, /*
        pseudo code <g> */<br>
        |                                            23 /* index of
        entry */,<br>
        |                              &arg);<br>
        <br>
        An on ELF side:<br>
        | static NTSTATUS my_func_23(void* parg)<br>
        | {<br>
        |   struct xxx_yyy *arg = parg;<br>
        |   /* do the hard work */<br>
        | }<br>
        |<br>
        | /* other functions */<br>
        |<br>
        | entry_point_table[] = {<br>
        |   /* ... */<br>
        |   my_func_23, /* index 23 */<br>
        |   /* ... */<br>
        | };<br>
        |<br>
        | /* a bit of black magic to register the entry_point_table */<br>
        <br>
        Keep in mind:<br>
        - the same structure can have different sizes for fields, and
        different layouts<br>
          when compiled for PE or ELF, 32 or 64 bit, or different CPUs.<br>
          So the ELF part must handle those discrepancies if any.<br>
        - pointers will be of different sizes...<br>
        - allocation of memory can be harder to implement on ELF side
        (as one must<br>
          ensure that allocated memory can be accessed from 32 bit PE
        part)<br>
        - exception handling?<br>
        <br>
        Actually, there will be two distinct tables:<br>
        - one used for the invocation from 64 bit PE side,<br>
        - the second one used for the invocation from 32 bit PE side.<br>
        <br>
        Upon invocation, their argument will be mapped to the 32 bit or
        the 64 bit<br>
        layout of the argument structure.<br>
        This allows either to adapt the implementation to any difference
        between the 32<br>
        and 64 bit worlds.<br>
        <br>
        So the interface between the PE module and its .so counterpart
        has to be<br>
        designed with care:<br>
        + as already stated, no callback from ELF part into PE part is
        available,<br>
        + some objects can be defined differently from both sides:<br>
          - integers (int) doesn't have the same size<br>
          - pointers are either 32 bit or 64 bit entities... so if
        memory has to be<br>
            returned to PE side, it must be in lower part of memory (at
        least for 32 bit<br>
            "syscalls")<br>
          - ...<br>
        <br>
        So the migration of a module from the "old" model to this PE
        model requires to:<br>
        - define the API between the PE and the ELF parts<br>
        - ensure that code in the ELF doesn't call back into PE APIs<br>
        - call through the Unixlib mechanism between the PE and ELF
        part.<br>
        - the Unixlib call mechanism is available even if the module is
        generated in the<br>
          old model, hence allowing to put the unixlib API in place
        still using the old<br>
          model. When all is migrated to the Unixlib interface, module
        can be generated<br>
          using the new module.<br>
          (it may be that after reading this you need either/or a) a
        break, b) a deep<br>
          breath, c) check your aspirin stock and d) restart from the
        beginning)<br>
        <br>
        TODO:<br>
        - debugging<br>
        - sketch the ARM/Intel on Darwin<br>
        <br>
        Additional bits:<br>
        ---------------<br>
        From the .so files that Wine used to link to, some of them are
        not tied to the<br>
        physical system, and can be available directly as PE modules
        (eg. JPEG decoder,<br>
        XML reader/writer...). The most important of those libraries are
        cross-compiled,<br>
        and their source code inserted into Wine tree (see libs/).<br>
        It's also possible to load the system-wide equivalent PE modules
        when installed.<br>
        <br>
        It's still not clear to me how the new module wow64 will be
        activated.<br>
        <br>
        [1]: on 64 bit, Windows chose the LLP64 integer model, while
        Unix chose the LP64<br>
        one (sur. The main difference is that long is 32 bit on Windows
        and 64 bit on<br>
        Unix.<br>
        In the old model, as compilation was native, the Windows types
        were redefined to<br>
        fit the LP64 model (like DWORD was an unsigned int to get the
        right size).<br>
        With the migration to the new model, as compilation of PE
        modules is done on<br>
        LLP64 models, DWORD (and friends) are now defined as on Windows
        as an unsigned<br>
        long.<br>
        This is called the migration to long types (90% of modules
        migrated) and takes<br>
        place along side the PE migration.</font></p>
    <br>
  </div>

</blockquote></div>