Re: [PATCH] ld: pep: Stop emitting reference to the pseudo-relocator function

LIU Hao <[email protected]>
Newsgroups gmane.comp.gnu.mingw.w64.general,gmane.comp.gnu.binutils
Message-ID <[email protected]>
在 2026-7-10 20:40, Jan Beulich via Mingw-w64-public 写道:
> The other aspect I'd like to understand a little better before (possibly)
> ack-ing is why pseudo-relocations need producing in the first place. If
> ld's generating of real relocations still isn't good enough, maybe that
> wants fixing? Then the question of whether a reference to that function is
> needed simply vanishes.

It's needed by code that uses dllimport'd data without marking them `dllimport`. In C++, vtables of 
polymorphic classes are also data, and there's a lot of code which doesn't apply `dllimport` to classes 
(boost for example).

This makes some sense - if a header uses explicit `dllimport` then it will usually be unusable with 
static libraries. Not having explicit `dllimport` enables headers to be used with either a static library 
or a DLL.


When a call to a function without `dllimport` is made, the compiler generates:

    call  target_function

which is provided by an import library (lib*.dll.a) and effects an indirect tail call:

    target_function:
        jmp  [rip + __imp_target_function]

x86-32 is similar, except for name decoration and address size, and the address is absolute instead of 
being RIP-relative.

And when a call to a function with `dllimport`, the compiler doesn't go through the thunk, and it just 
generates:

    call  [rip + __imp_target_function]


As for dllimport'd data, given C code:

    extern int plain_data[];
    int get_plain_data_1(void) { return plain_data[1]; }

    __declspec(dllimport) extern int dllimp_data[];
    int get_dllimp_data_1(void) { return dllimp_data[1]; }


Compiling this with `gcc test.c -O2 -mcmodel=small -S` gives:

    get_plain_data_1:
        mov  eax, [rip + plain_data + 0x4]    # eax = plain_data [1]
        ret

    get_dllimp_data_1:
        mov  rax, [rip + __imp_dllimp_data]   # rax = __imp_dllimp_data
        mov  eax, [rax + 0x4]                 # eax = *(int*) (rax+4)
                                              #     = (*__imp_dllimp_data) [1]
        ret


`get_plain_data_1` references the relocation `plain_data + 0x4` which is not dllimport'able; and the 
linker is not able to rewrite it to the latter, which would take more space.


This is solved in three steps. First, by default (mingw-w64 GCC without `-mcmodel=small`, or Clang 
without `-fno-auto-import`) the compiler must always reference a datum outside the current translation 
unit through a level of indirection. Compiling the above example with `gcc test.c -O2 -S` gives:

    get_plain_data_1:
        mov  rax, [rip + .refptr.plain_data]   # rax = .refptr.plain_data
        mov  eax, [rax + 4]                    # eax = *(int*) (rax+4)
                                               #     = (*.refptr.plain_data) [1]
        ret

As on x86-64 the 32-bit displacement is incapable of covering the full 64-bit address space, this level 
of indirection allows access of an arbitrary 64-bit address.

Second, with `--enable-auto-import`, the linker sets `.refptr.plain_data` to `&__imp_plain_data` (the 
address of `__imp_plain_data`), and generates pseudo-relocation information for it.

And finally, `_pei386_runtime_relocator()` (despite its name) in mingw-w64 CRT reads the 
pseudo-relocation information, and sets `.refptr.plain_data` to the value in `__imp_plain_data`, which is 
the absolute address of the imported datum in the DLL. User code can now access the datum through 
`.refptr.plain_data`.

(I have omitted some details in here; what `_pei386_runtime_relocator()` actually does is 
`.refptr.plain_data += __imp_plain_data - &__imp_plain_data`. Initially `.refptr.plain_data` has a value 
of `&__imp_plain_data` so this can be simplified to `.refptr.plain_data = __imp_plain_data`.)


-- 
Best regards,
LIU Hao

_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
OpenPGP_signature.asc (application/pgp-signature, 840 B)
-----BEGIN PGP SIGNATURE-----

wsF5BAABCAAjFiEEYmSQWY4DEzq4FUs4hfveZl3ogBsFAmpU4UYFAwAAAAAACgkQhfveZl3ogBuB
hg/+OJsjZWqbt/yXACnkP7HsaHVW5cWHlcjMTIJHR6KVCDoD9+uxprboiHTfbyP8HCT7aZt1+SIt
kJVns6F1cCai8/wsfEixsCyN0iNyFqzTtLh5wOaJqFSYDsIanyX5AW2Tw/1WIU61vSnTxuKobxEW
/0MKVZAYVkqrE6hp3bnx8u5ONm5Cj97qdnxQkKExejetffyRUAzwYNdTbe1YRCS/M7HxXj3DvkbM
0utiu7qx1c4tODQh9FC4ZDQbUizKr3nJr/fFkGJlV7EBzS1P5mZgDyAvMu2trA3WLHV1/esOG0xO
R4r4L33a3IKA4lgPhGgqo3CZ9mNG2enTZs9v7qNDTmGkPjlS6URCkkTOtBLrmf740uz8BWZ3JdLp
394vImrxy8+ZQOT5RY9vFArGDMN8p/AYAykKt8d3dse6+O9g1jKEMjyzXpeubKBoIAYCQEZTjO+T
mwkRdZfeJCDq/cpTAsIEAaS88A3M3DR1NmSGkEcwyam7PyiMFDWVKuiNXN4bOKDbGz5zJsL+NN9x
/uwKnm9jOGQVv94paW68agblOSfpxDLWE180zwY8h9gbRqxrmIBsIFUmN9MB2Etd38FIhfyNX8Mt
1sM8wmjhU2ppRUT1V6wZ2WL3clUPSLEyD3UXXh/YWCl+iTWwhZEv2YQYR1BaPWoE8mf3cdTBLmeI
x08=
=3ZLT
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.